首页 > 代码库 > 代码即数据思想带来的思考

代码即数据思想带来的思考

前言:

首先大家都听说过“代码即数据”这句话,但是这里要说的“代码即数据”可能会有不同的意思,个人的意思是,我们在开发过程中有好多的时候是数据信息驱动或者状态驱动的。

说的白话些,就是我们之前的好多开发都有明确的业务需求,同时开发过程中会使用我们熟练的解决方案。但是有的时候上手一个自己之前完全不熟悉的项目或者在项目中使用了我们不擅长的一些组件或技术的时候,一切的开发似乎变得不可控了。这个时候的驱动往往就变成了针对于我们真正关心的数据的处理。比如,我们针对于一些需求想好了解决方案,但是在执行与实施过程中可能会出现一些不可控的因素使得我们不得不改变到新的解决方案上去,这样的话有可能之前已经code的代码必须重来,同时从原有的业务逻辑中剥离代码也将是一个痛苦的过程。但是不变的就是我们所要去处理的数据,这就是我所说的”数据信息驱动“。

那么”代码及数据“的核心是什么?

核心就是把控整个项目的数据生命中数据状态的变化。针对于每一个状态变化节点,这些变化的东西扔给代码之外的组件进行管理控制。

2个例子:

比如之前听说过一个哥们自己开发推荐系统,由于他对于推荐系统的搭建完全不熟悉,并且不确定哪些数据可用,所以他决定先把架子搭起来,但是后期的算法Code他准备通过文本文件的形式加入系统中,于是此后的程序执行方式就变成了,程序加载到一些指定地方时候会读取文本文件,再将文件信息当作程序的一部分进行执行。(听着有没有一种TDD的赶脚),由于之前的代码是由他们的CTO使用perl写的,后来项目完全交由这个哥们负责,考虑到自己不熟悉prel并且在某些嵌套算法中Perl的效率很低,于是他又将一些核心的算法从主程序中剥离出来(perl的那一部分),考虑后期使用自己熟悉的python实现,所以最终的系统就是这个由中程序框架负责业务+数据流转,细节实现+变化拓展交由文本数据代码实现,取得了不错的成绩。

 

第二一个例子是一个哥们也是做一个数据流转系统,但是在数据流转过程当中会经由不同的操作系统及终端,并且在开发过程中接入了很多现有的解决方案帮助细节处理,所以他的设计方式是在每一次临界点的时候进行结扎,细节处理交由程序外控制,这就是所说的“分部式”,每一步你可以放在DB中,也可交由文本文件或其他组件。

 

一个小例子:

考虑到python,php的弱类型,以及C#的强类型,我们将数据的处理需要依赖反射实现。

比如业务为:

 

由于这种方式最重要的就是识别出变化的位置与节点并将其脱离开来。

例子结构如下:

我们将适配的方式完全交由反射处理,建立TaskHandlerMap.xml

<?xml version="1.0" encoding="utf-8" ?>
<TaskHandlerClassMap>
  <TaskHandlerItem>
    <FunctionName>CreateDisk</FunctionName>
    <TaskHandlerName><![CDATA[DiskOperation]]></TaskHandlerName>
    <MessageModelName><![CDATA[DiskMessage]]></MessageModelName>
  </TaskHandlerItem>
  <TaskHandlerItem>
    <FunctionName>CreateVm</FunctionName>
    <TaskHandlerName><![CDATA[VitureMachineOperation]]></TaskHandlerName>
    <MessageModelName><![CDATA[VirtualMachineMessage]]></MessageModelName>
  </TaskHandlerItem>
</TaskHandlerClassMap>

我们在TaskManager模仿一个消息的传递与接受:

    public class TaskManager
    {
        public void DoWork() {

            string json = @"{JobMethod:‘CreateDisk‘,DiskId:1,VirtualMachineId:1,DiskName:‘testDisk01‘}";

            TaskHandlerItem taskHandlerItem = ReflectInterface.GetMessgeTaskHandlerInstance(json);
            ITaskHandler taskHandler = ReflectInterface.GetTaskHandler("RabbitMQ.Reflect", "RabbitMQ.Reflect.TaskHandlerClass." + taskHandlerItem.TaskHandlerName.ToString());
            BaseMessage baseMessage = ReflectInterface.GetBaseMessage("RabbitMQ.Reflect", "RabbitMQ.Reflect.TaskMessage." + taskHandlerItem.MessageModelName.ToString(), json);
            if (taskHandler != null) {
                taskHandler.TaskProgress += taskHanadler_TaskProgress;
            }


            Thread workThread = new Thread(taskHandler.DoWork);
            workThread.IsBackground = true;
            workThread.Start(baseMessage);
        }

        void taskHanadler_TaskProgress(TaskHandlerEventArgs e)
        {
            String returnMessageJson = e.ToString();

            //update message table
            System.Console.WriteLine(e);
        }
    }

对应的核心反射处理类:reflectInerface:

{
    public class ReflectInterface
    {
        static String _xmlpath = @"D:\zcj-project\RabbitMQ.Console.Client\RabbitMQ.Reflect\TaskXmlMap\TaskHandlerMap.xml";
        //get messageTaskHandler instance by message
        public static TaskHandlerItem GetMessgeTaskHandlerInstance(string message)
        {
            try
            {
                JObject jObject = JObject.Parse(message);
                String methodName = jObject["JobMethod"].ToString();
                return SerializerXml(methodName);
            }
            catch (Exception ex) {
                throw ex;
            }
        }

        //get xml serializer info
        private static TaskHandlerItem SerializerXml(String jobMethod)
        {
            TaskHandlerItem taskHandlerItem = null;
            using (Stream stream = new FileStream(_xmlpath, FileMode.Open, FileAccess.Read))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(TaskHandlerClassMap));
                TaskHandlerClassMap _taskHandlerClassMap = serializer.Deserialize(stream) as TaskHandlerClassMap;
                if (_taskHandlerClassMap != null) {
                    foreach (TaskHandlerItem _taskHandlerItem in _taskHandlerClassMap.TaskHandlerItems)
                    {
                        if (_taskHandlerItem.FunctionName == jobMethod) {
                            taskHandlerItem = new TaskHandlerItem();
                            taskHandlerItem.MessageModelName = _taskHandlerItem.MessageModelName;
                            taskHandlerItem.TaskHandlerName = _taskHandlerItem.TaskHandlerName;
                            break;
                        }
                    }
                }
            }
            return taskHandlerItem;
        }

        //get ITaskHandler instance
        public static ITaskHandler GetTaskHandler(string assemblyName, string classNameSpace)
        {
            try
            {
                object instance = Assembly.Load(assemblyName).CreateInstance(classNameSpace);
                if (instance != null)
                {
                    return (ITaskHandler)instance;
                }
                else
                {
                    throw new Exception("did not find instance");
                }
            }
            catch (Exception ex) {
                throw ex;
            }
        }

        //get BaseMessage instance
        public static BaseMessage GetBaseMessage(string assemblyName, string classNameSpace,string message)
        {
            try
            {
                object instance = Assembly.Load(assemblyName).CreateInstance(classNameSpace);
                if (instance != null)
                {
                    object messageModel = JsonConvert.DeserializeObject(message,instance.GetType());
                    return messageModel as BaseMessage;
                }
                else
                {
                    throw new Exception("did not find instance");
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }

    public class TaskHandlerClassMap {
        [XmlElement("TaskHandlerItem", IsNullable = false)]
        public List<TaskHandlerItem> TaskHandlerItems { get; set; }
    }

    public class TaskHandlerItem
    {
        [XmlElement("FunctionName", IsNullable = false)]
        public String FunctionName { get; set; }

        [XmlElement("TaskHandlerName", IsNullable = false)]
        public String TaskHandlerName { get; set; }

        [XmlElement("MessageModelName", IsNullable = false)]
        public String MessageModelName { get; set; }

    }
}

建立TaskHandler类的方法:

    public interface ITaskHandler:IDisposable
    {
        event Action<TaskHandlerEventArgs> TaskProgress;
        void DoWork(object baseMessage);
    }

    public class TaskHandlerEventArgs : EventArgs
    {
        private object _messageModel;
        public TaskHandlerEventArgs(object messageModel) {
            this._messageModel = messageModel;
        }
        public String Message {
            get { return _messageModel.ToString(); }
        }
    }

AbstractTaskHandler:

    public abstract class AbstractTaskHandler:ITaskHandler
    {
        public abstract void DoWork(object baseMessage);
        public void Dispose()
        {
            Thread.CurrentThread.Abort();
        }

        public abstract event Action<TaskHandlerEventArgs> TaskProgress;
    }

具体的业务实现类:Disk:

    public class DiskOperation : AbstractTaskHandler
    {
        public override void DoWork(object baseMessage)
        {
            DiskMessage message = baseMessage as DiskMessage;
            string result = "class name is : DiskOperation";
            TaskProgress(new TaskHandlerEventArgs(result));
            base.Dispose();
        }

        public override event Action<TaskHandlerEventArgs> TaskProgress;
    }

以及VM:

    public class VitureMachineOperation : AbstractTaskHandler
    {
        public override void DoWork(object baseMessage)
        {
            string result = "class name is : VitureMachineOperation";

            TaskProgress(new TaskHandlerEventArgs(result));
            base.Dispose();
        }

        public override event Action<TaskHandlerEventArgs> TaskProgress;
    }

建立对应的Message信息:

    public class BaseMessage
    {
        public String JobMethod { get; set; }
        public String Uuid { get; set; }
    }
    public class DiskMessage:BaseMessage
    {
        public String DiskId { get; set; }
        public String VirtualMachineId { get; set; }
        public String DiskName { get; set; }
    }
    public class VirtualMachineMessage:BaseMessage
    {
        public String VirtualMachineId { get; set; }
        public String VirtualMachineName { get; set; }
        public String UserName { get; set; }
    }

这样在我们将程序处理的调度交给xml配置,包括后期的sql也可以放进去,减少了后期由于解决方案更改带来的维护不便利的问题。