话说小菜过做已近3年,虽出身PHP后项目大多涉及.net,系统也做得比较繁杂,从常见的CMS,企业OA,ERP,也涉及到电商系统的开发定制,爬虫,工具不一而足,其中web系统居多。

由于表现良好,时常会被经理叫去:“小菜,人是需要成长的啊,不如下个项目你负责吧,锻炼一下吧。”可是小菜对这种负责的职位是相当的不感冒,小菜只想快乐的编码,小菜的最终成为soho一族陪着美女环游世界。都知道事情一涉及到管理,负责就不那么纯洁了。并且小菜一直认为:将帅无能,累死三军。于是小菜每次都以“更对编码感兴趣” 为由拒绝。然而小菜知道丑媳妇早晚要见公婆,时间久了,这一步总是要过的,于是小菜也每每在项目之前,之后尝试以自己的理解,去搭一个架子,以备将来负责时不时之需。

于是“小菜白话搭架子”系列便出现了,会结合一些项目进行分析与记录,促进成长,水平有限,不喜勿喷哦。

闲话少绪,小菜给大家道一下整个的项目背景。

背景:此项目是为欧美某信息服务公司A加工其世界范围内所合作的的“信息提供商”提供的信息。也就是为A设计开发一个数据处理管道使用其不同的合作商,使不同合作商的数据最终为A所用。

由于小菜公司与A公司长久合作关系,大部分的合作商数据处理工具以开发完成,目前小菜们所要做的架子主要是将这些工具组合在一起,使开发过程减少人工干扰,减少人工成本。同时可适用于未来的需求扩展。

开发完成的Tool,及步骤:

  1. DownloadTool:从信息提供商下载数据。
  2. Diff:为数据提供商本身数据去重。
  3. Caculate:整合新版本数据与库中数据,生成新数据。
  4. View:生成用户可用数据。
  5. Backup:数据备份。

因为小菜认为做开发解决方案一定要在技术选型之前,如果先做技术选型的话,可能会我们的思考产生束缚,

小菜第一次获取以上信息时,由于这么多的Tool,将来还可能扩展,本能的想到了一个模型,就是ToolBox。

这样的话,将来那些新开发的Tool或已有的Tool之间就不需要产生本质的结合,将来我们就需要将他们扔进一个叫做“Toolbox"的文件夹中,MainServer会检索这个文件夹,将新增的Tool加载进系统运行程序集,有些类似于插件开发。由于经理对于Wcf有个人的青睐,要求使用wcf做选型的分布式信息架构,说实话小菜不喜欢wcf,因为小菜一直认为这又是微软的一个学院派产品,配置麻烦也不酷。不过用就用吧。

于是小菜认为,既然头脑中有了模型,技术有了选型,开始最喜欢的代码吧:

小菜的结构与分层大概是这样的:

小菜为每一个Tool都做了一个接口,MainServer和Tool之间通过wcf进行通信,mainserver通过检测Tool的心跳获知其生活状态,Tool内有一个线程定时回调方法去Mainserver查找有没有分配自己的Task,Tool获取Task之后执行,返回给客户端:

代码如下:

server.contract:

[ServiceContract]

public interface IView {

[OperationContract]

Int32 CreateWork(UpstreamViewsWF work, Int32? seriesID);

[OperationContract]

Boolean TryTakeWork(out GeneralWork<UpstreamViewsWF> work);

[OperationContract]

void UpdateWork(GeneralWork<UpstreamViewsWF> work);

[OperationContract]

void DeleteWork(Int32 id);

[OperationContract]

void ReportProcess(WorkProgress progress);

[OperationContract]

void ReportCompletion(GeneralWork<UpstreamViewsWF> work);

}

service:

public class View: ApplicationService, IView {
private Logger _logger;
private IGeneralJobRepository _generalRepo;
private IJobStatusHistoryRepository _historyRepo; public ViewsService(
IRepositoryContext context,
IGeneralJobRepository generalJobRepo,
IJobStatusHistoryRepository historyRepo)
: base(context) {
_generalRepo = generalJobRepo;
_historyRepo = historyRepo;
_logger = LogManager.GetCurrentClassLogger();
} public Int32 CreateWork(Views work, Int32? seriesID) {
_logger.Info(String.Empty);
GeneralJob job = new GeneralJob {
Category = (Byte)WorkCategory.Views,
Status = (Byte)WorkStatus.Created,
}; if (seriesID.HasValue && seriesID.Value > 0) {
job.SeriesID = seriesID.Value;
} work.TypeName = WorkCategory.Views.ToString(); job.VARS = JsonConvert.SerializeObject(work);
try {
Context.BeginTrans();
_generalRepo.Create(job);
_historyRepo.Create(CreateJobStatus(job)); Context.Commit();
return job.ID;
}
catch (Exception ex) {
_logger.ErrorException(String.Empty, ex);
throw FaultData.CreateFaultException(ex);
}
} public GeneralWork<Views> RetriveWork(int id) {
_logger.Info(String.Empty);
try {
GeneralJob job = _generalRepo.RetriveByKey(id);
return job.Map<Views>();
} catch (Exception ex) { _logger.ErrorException(String.Empty, ex); throw FaultData.CreateFaultException(ex); } } public void UpdateWork(GeneralWork<Views> work) { _logger.Info(String.Empty); try { GeneralJob job = _generalRepo.RetriveByKey(work.ID); if (job.Status != (Byte)WorkStatus.Created) { Exception ex = new Exception("Only new work could be modified"); } work.VARS.TypeName = WorkCategory.UpstreamViewsWF.ToString(); job.SeriesID = work.SeriesID; job.VARS = JsonConvert.SerializeObject(work.VARS); Context.BeginTrans(); _generalRepo.Update(job); _historyRepo.Create(CreateJobStatus(job)); Context.Commit(); } catch (Exception ex) { _logger.ErrorException(String.Empty, ex); throw FaultData.CreateFaultException(ex); } } public void DeleteWork(Int32 id) { _logger.Info(String.Empty); try { GeneralJob job = _generalRepo.RetriveByKey(id); if (job.Status != (Byte)WorkStatus.Created) { Exception ex = new Exception("Only new work could be modified"); } job.Status = (Byte)WorkStatus.Abandoned; Context.BeginTrans(); _generalRepo.Delete(job); _historyRepo.Create(CreateJobStatus(job)); Context.Commit(); } catch (Exception ex) { _logger.ErrorException(String.Empty, ex); throw FaultData.CreateFaultException(ex); } } public void ReportProcess(WorkProgress progress) { _logger.Info(String.Empty); } public void ReportCompletion(GeneralWork<Views> work) { _logger.Info(String.Empty); try { GeneralJob job1 = work.Map<Views>(); job1.Status = (Byte)WorkStatus.Finished; Context.BeginTrans(); _generalRepo.Update(job1); _historyRepo.Create(CreateJobStatus(job1)); Context.Commit(); } catch (Exception ex) { _logger.ErrorException(String.Empty, ex); throw FaultData.CreateFaultException(ex); } } public GeneralWork<Views>[] ReadWorkQueue(int currentPage, int itemsPerPage, WorkStatus? status, string key, outPageClause pageClause) { _logger.Info(String.Empty); try { List<Expression<Func<GeneralJob, Boolean>>> filters = new List<Expression<Func<GeneralJob, bool>>>(); filters.Add(e => e.Category == (Byte)WorkCategory.UpstreamViewsWF); if (status.HasValue) { filters.Add(e => e.Status == (Byte)status); } if (!String.IsNullOrWhiteSpace(key)) { filters.Add(e => e.VARS.Contains(key.Trim())); } PageClause<GeneralJob> jobs = _generalRepo.RetriveAll(currentPage, itemsPerPage, true , p => p.ID, filters.ToArray()); pageClause = new PageClause(jobs); return jobs.Map<UpstreamViewsWF>().ToArray(); } catch (Exception ex) { _logger.ErrorException(String.Empty, ex); throw FaultData.CreateFaultException(ex); } } }

对Tool的封装:

class Program

{

static lWork<View> currentWork;

private readonly static string exePath = Path.Combine( AppDomain.CurrentDomain.BaseDirectory, "app.exe" );

static void Main( string[] args ) {

Trace.Listeners.Add( new ConsoleTraceListener() );

try {

if( TryTakeWork() ) {

Trace.WriteLine( "Take a work" );

Work();

ProcessWork();

ReportCompletion();

}

} catch( Exception ex ) {

Console.WriteLine( ex );

}

}

static void Work() {

using( ServiceFactory factory = new ServiceFactory() ) {

try {

ISeriesWorkService service = factory.CreateChanel<ISeriesWorkService>();

SeriesWork seriesWork = service.RetriveWork( currentWork.SeriesID );

currentWork.VARS.TypeName = ConfigurationManager.AppSettings[ "TypeName" ];

Trace.WriteLine( "TypeName:" + currentWork.VARS.TypeName );

currentWork.VARS.Code = seriesWork.egion;

Trace.WriteLine( "Code:" + Code );

CopyHelper.CopyDir( Path.GetFullPath( @"..\..\Application\" ), AppDomain.CurrentDomain.BaseDirectory );

} catch( Exception ex ) {

Console.WriteLine( ex );

}

}

}

static Boolean TakeWork() {

Trace.WriteLine( "TryTakeWork" );

using( ServiceFactory factory = new ServiceFactory() ) {

IUpstreamViewsWFService service = factory.CreateChanel<IUpstreamViewsWFService>();

return service.TakeWork( out currentWork );

}

}

static void ProcessWork() {

Trace.WriteLine( "ProcessWork..." );

Process process = null;

try {

ProcessStartInfo info = new ProcessStartInfo();

info.CreateNoWindow = false;

info.FileName = exePath; //as u need

process = Process.Start( info );

process.EnableRaisingEvents = true;

process.WaitForExit();

Trace.WriteLine( "ProcessWork succeed" );

} catch( Exception EX ) {

Trace.WriteLine( "Exception:" + EX );

if( process != null ) {

process.Kill();

}

}

}

static void ReportCompletion() {

Trace.WriteLine( "ReportCompletion" );

using( ServiceFactory factory = new ServiceFactory() ) {

IView service = factory.CreateChanel<IView>();

service.ReportCompletion( currentWork );

}

}

}

话说一天过去了,小菜把基本的功能完成了,小菜想反正也有时间于是小菜把他知道的东西都用上了IOC(unit),Log4,Orm(ef)。慢慢的小菜开始将接口丰富了越来越多的功能,最后小菜对经理说了自己的想法,说了用的技术,经理说好"下午部署上吧“,小菜心想我的接口已经有了很丰富的功能,我还提供了很多其他功能的接口,肯定没问题于是小菜欣然的答应了。然而新的挑战就这样悄然的反生了。

他找到每个Tool的开发人员讲解自己的接口怎样用,能做什么,需要与MainServer以怎样的方式进行通信,不同异常机制信息的提供的不同。小菜发现他对每一开发者讲解的时候,大家更多的是关心自己的Tool应该更少的关注Mainserver,同时大家也更多的是忙于自己的事情,没有多少时间去协同维护你的接口,大家的一致决定是你先写一个Tool对接Mainserver的Demo我们照着改就可以了,你先写吧。

就这样小菜心想,我已经写的这么好了的接口,为什么大家不喜欢用不喜欢听呢。下班之后小菜一直不思其解,于是拨通了同校大两级也是做开发的学长”老鸟“的电话,简单介绍了事情的经过之后,老鸟呵呵一笑说:“小菜, 你的想法不错,可是就是因为你提供的东西反而太多了,大师不是只懂加法也要会做减法,搭架子要有所为有所不为”。

未完待续。。。

 
 

ToolBox Analysis & Design的更多相关文章

  1. [Design Patterns] 3. Software Pattern Overview

    When you're on the way which is unknown and dangerous, just follow your mind and steer the boat. 软件模 ...

  2. matlab toolboxes 大全

    MATLAB Toolboxes top (Top) Audio - Astronomy - BiomedicalInformatics - Chemometrics  - Chaos - Chemi ...

  3. 软件开发学习笔记 <二>软件开发模型、Up、Rup、敏捷Up

    软件开发过程(process) 是一个将用户需求转化为软件系统所需要的活动的集合. 软件生命周期(SDLC,Software Devlopment Life Cycle) 软件从孕育.诞生.成长.成熟 ...

  4. DDD~概念中的DDD(转)

    概念中的DDD DDD: 领域驱动设计,它是对面向对象的的分析和设计(OOAD,Object Orient Analysis Design)的一个补充,对技术框架进行了分层规划,同时对每个类进行了策略 ...

  5. C++的学习资源

    本文总结了几个好的C++网站,以及C++方面的经典书籍.所列书籍或标准可以到这里找找电子版. wikipedia关于C++有关条目,注意看后面“参考文献”和“外部链接”: C++ programmin ...

  6. 读书笔记系列之java性能优化权威指南 一 第一章

    主题:java性能优化权威指南 pdf 版本:英文版 Java Performance Tuning 忽略:(0~24页)Performance+Acknowledge 1.Strategies, A ...

  7. DDD的思考

    概述 DDD领域驱动设计,它是对面向对象的的分析和设计(OOAD,Object Orient Analysis Design)的一个补充,对技术框架进行了分层规划,同时对每个类进行了策略和类型划分.领 ...

  8. UML Distilled - Development Process

    Iterative(迭代) and Waterfall(瀑布) Processes One of the biggest debates about process is that between w ...

  9. LiangNa Resum

    LiangNa AnShan Street, YangPu, NY @.com OBJECTIVE: Seeking a position to contribute my skills and ed ...

随机推荐

  1. 模拟linux下的ls -l命令

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h&g ...

  2. JavaEE(2) - Weblogic 服务器执行JNDI绑定和查找

    1. 应用服务器默认添加的系统属性 NetBeans创建java web project(ctxTest) (index.jsp) <%@page import="java.util. ...

  3. Codeforces 135A-Replacement(思维)

    A. Replacement time limit per test 2 seconds memory limit per test 256 megabytes input standard inpu ...

  4. OOP 创建对象的7种方式

    JavaScript OOP 创建对象的7种方式   我写JS代码,可以说一直都是面向过程的写法,除了一些用来封装数据的对象或者jQuery插件,可以说对原生对象了解的是少之又少.所以我拿着<J ...

  5. hdu Color the ball

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1556 树状数组的  update的应用,逆序更新 代码: #include <stdio.h&g ...

  6. 利用缓存、Timer间隔时间发送微信的实例,很有用的例子

    //Class WechatOfferExcutor 此类为微信触发类,属于上层调用类,其中有用到用静态变量缓存offer信息,Task异步执行发送方法等 using Newtonsoft.Json. ...

  7. iOS开发之protocol和delegate

     protocol--协议 协议是用来定义对象的属性,行为和用于回调的.     协议中有两个keyword@private和@optional,@private表示使用这个协议必需要写的方法,@op ...

  8. POJ 2109 :Power of Cryptography

    Power of Cryptography Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 18258   Accepted: ...

  9. 使用myeclipse将Javaj项目标ar套餐邂逅classnotfound解决问题的方法

    做一件事的今天,该Java项目打包成jar文件.折腾2小时,最终运行jar文件报告classnotfound异常,我觉得程序写入依赖jar包不玩成,但是,我手动添加.或不.网上找了很多办法.或不.后. ...

  10. 解决Crystal Report XI R2不能在64操作系统正常工作的问题-web程序

    原文:[原创]解决Crystal Report XI R2不能在64操作系统正常工作的问题-web程序 我更换了新的电脑,操作系统也从原来32位的windows 2003 R2升级到windows 2 ...