领域驱动设计学习(1)

今天学习了领域驱动设计的导学,算是对DDD(Domain Driven Design)有了一个初步的认识。下面是学习中归纳的一些信息,主要围绕六个问题展开。

  • 1.什么是DDD
  • 2.DDD解决了什么问题
  • 3.领域如何划分
  • 4.聚合和领域之间的关系
  • 5.战略建模与战术建模谁更重要
  • 6.ORM与领域建模

1.什么是DDD

Domain Driven Design,领域驱动设计,那么什么是领域呢?领域就是业务,这里的领域是分层的。大致可以分为:实体、值对象、聚合、领域服务和领域事件等。

2.DDD解决了什么问题

解决软件的复杂性问题。

3.领域如何划分

按功能划分

4.聚合和领域之间的关系

聚合是领域的核心概念,在领域驱动设计中,大的对象实体是由小的对象实体聚合起来的。在想要访问某个小的对象实体时,需要以大的对象实体为入口进行访问。这规定了对象之间的边界,避免了一个对象被很多地方混乱的调用的情况,降低模型的复杂度。(很拗口,不知能不能被理解)

5.战略建模和战术建模谁更重要

当然,两个都很重要。但是,可以确定的一点就是,战术更难。讲到战术和战略,就不得不提领域驱动设计经典的两本书。
第一本是04年出版的DDD,它全书是以自下向上的方式写的,从细节的战术开始写,一直到第四部分,才讲到战略。当然,这是因为年代的不同,04年的时候流行自下向上的开发方式。
第二本是13年出版的IDDD,实现领域驱动设计,它采用的是自顶下下的方式,从战略开始写,后面才讲到战术。当然,这是有原因的。到了13年,微服务开始兴起,因此小公司也可以先考虑战略,将整个软件分为几个微服务模块进行开发。
上面两本书的区别也会影响到学习DDD时,如何阅读这两本书的顺序。这个之后再谈。

6.ORM与领域建模

ORM和领域建模不是一个东西。ORM其实就是DAO(data access object),它最多跟领域模型最底部的Repository概念类似,且也不全然相同。可以这么说,Repository可以用ORM实现,但ORM并不是repository。

上述是根据本次技术交流做的总结,有问题请指出,祝进步。
yaoel
2017年5月19日

参考:
1.领域驱动设计
2.实现领域驱动设计
3.Domain-Driven-Design-Example

关于traefik报:http: server closed idle connection问题的分析和解决

现象

软件新版本上线后,系统经常时不时的出现500 Internal Server Error502问题。

探查

下面是软件的大体架构

1
SLB<---->traefik<--->uwsgi<---->web server

请求从浏览器客户端发起,先到负载均衡,然后负载均衡转发到traefik,traefik再转发到具体的服务器某个端口;服务器端口后面是实际的web服务,当然,先通过uwsgi层再进入web server。
当出现500 Internal Server Error时,去查看具体的请求,发现三个蛛丝马迹:

1.客户端同时发送了多个相同请求;
2.在web server的日志中看不到对应的请求报文;
3.traefik日志中出现:time="2017-03-20T03:43:17Z" level=warning msg="Error forwarding to http://xx.xx.xx.xx:8888, err: http: server closed idle connection”错误;
4.所有request headers和response headers中都带有Connection: keep-alive

分析

1.请求在traefik和uwsgi之间中断了;
2.跟http的长连接有关系;

解决

对于相同请求,第一个请求过来,带了Connection:keep-alive头,traefik认为跟uwsgi建立了长连接通道,但由于uwsgi没有支持长连接,在返回后就将连接关闭。当相同的第二个请求过来时,traefik还是使用之前的通道,而此时uwsgi已经关闭了连接,所以报错:http: server closed idle connection

再来看系统中uwsgi.ini:

1
2
3
4
5
6
[uwsgi]
......
http-socket = 0.0.0.0:5000
http-keepalive = 1
add-header=Connection: Keep-Alive
......

虽然看上去设置了http-keepalive,但是由于http-socket不支持keep-alive,所以无用。
正确的配置方式如下:

1
2
3
4
5
6
[uwsgi]
......
http = 0.0.0.0:5000
http-keepalive = 1
add-header=Connection: Keep-Alive
......

作者 @yaoel
2017 年 05月 11日

参考

1.Traefik sporadically failing when proxying requests
2.uWSGI Options
3.HTTP权威指南 4.5.6 Keep–Alive和哑代理
4.http-socket does not support Keep-Alive
5.uwsgi.ini配置参考

不做伪工作者

什么是伪工作者

在互联网行业中工作的程序员们都会有这样的感觉,每时每刻手上都有三四个任务甚至更多,并且完成两个之后,可能会冒出两个三个甚至四个,所有手上一直有很多任务。在面对这么多任务的时候,很多人会追求完成任务的个数,所以往往选择简单的任务开始做。虽然这样做,看似工作完成的比例还不错,但是很危险。虽然每天看似工作的满满的,但很可能并没有解决真正重要有价值的事情。甚至于不断的在做重复性工作,技术工作能力都没有得到提高,甚至下降。也得到不到公司的提拔。最终,既坑了自己,可坑了公司。这样的人就是伪工作者
当然,我们都不希望成为伪工作者,那么怎么成为一个‘’工作者呢?

如何成为’真’工作者

要能分辨手上哪些工作对公司的价值最大

很多公司并不看重你完成任务的数量,而更看重你所完成任务为公司产生的价值有多大。很多任务虽然很难,但是,如果这个事情很有价值,那就值得做。

要有主动性

虽然管理人员能下发很多任务,但光靠这样是不够的,员工也要主动去辨别哪些工作对公司有大的价值,然后提出来。现在,很多DevOps类型的开发都是直面一线客户的,所以他们可以,也完全能够提出一些有价值的建议。

使用时间四象限法则

时间四象限法则将事情分成四类,分别是:重要有紧急、重要不紧急、紧急不重要、不重要不紧急。
对以‘真’工作者为目标的我们来说,主要需要完成1、2,在有余力的时候再去做3、4。当然,这里还有一个重点,就是要梳理自己的任务,将他们分别代入这四象限之中。这样,就算任务满屏非,只要重点关注1和2就可以了。
时间四象限法则

祝进步
yaoel
2017年5月17日于上海

使用Flask-Migrate(alembic)实现MySQL表名修改、字段名修改和枚举类型修改

  • 表名修改
  • 字段名修改
  • 枚举类型增加枚举可选值

表名修改

由于之前创建的MySQL数据表名跟实际用处不符,所以需要修改表名,并保证数据不丢失。
若直接修改表名,然后使用命令python manage.py db migrate会删除后新建,导致数据丢失。为了保证数据不丢失,可以自己使用alembic语法编写升级脚本。语法如下:

1
op.rename_table('shop_print_rules', 'label_print_rules')

字段名修改

由于字段名名不副实,所以要对字段名进修改,并保证数据不丢失。
若字节修改字段名,然后使用命令python manage.py db migrate会删除后新建,导致数据丢失。使用下列语法可以保证数据不丢失,但需要自己编写升级脚本。语法如下:

1
2
3
4
op.alter_column('label_print_rules', 'box_template_type', new_column_name='template_type',
existing_type=sa.Enum('single_box', 'all_box', 'pick', 'putaway',
'stockin', 'stockout', 'delivery')
server_default='single_box')

枚举类型字段增加枚举可选值

当对枚举类型字段增加枚举可选值时,使用Flask-Migrate进行migrate不会检测到改动,所以需要手动写脚本。语法如下:

1
2
3
4
5
6
7
op.alter_column('label_print_rules', 'template_type',
existing_type=sa.Enum('single_box', 'all_box', 'pick', 'putaway',
'stockin', 'stockout', 'delivery'),
type_=sa.Enum('single_box', 'all_box', 'pick', 'putaway',
'stockin', 'stockout', 'delivery', 'single_picking_label',
'multi_picking_label', 'order_picking_label'),
server_default='single_box')

作者 @yaoel
2017 年 05月 09日

参考:
1.alembic.op.rename_table
2.Flask-Migrate升级MySQL字段时能否重命名而非删除后新建

caddy简介

什么是caddy?一个类似Nginx的东西。
最近在折腾将部署在github上的hexo博客迁移到自己的服务器上。偶然间知道了caddy这个神器,真的是一键部署博客
由于服务器是ubuntu 16.04版本的,下面是基于此版本进行的。

caddy的好处:

  • 一键启动
  • 一键https
  • 各种方便的配置

下载

caddy官网下载页面下载对应版本。然后使用scp将压缩文件拷贝到自己服务器。

1
scp ./caddy*.tar.gz root@xx.xx.xx.xx:/path/to/place/caddy***.tar.gz

##解压,然后将可执行文件拷贝在对应bin目录下(全局可运行)

1
2
tar -xzf caddy*.tar.gz caddy
mv ./caddy /usr/local/bin

进入你的博客目录运行

注意要有index.html文件,如果没有回报错

1
2
cd /your/blog/path
caddy

然后在服务器的2015端口就可访问博客。

##配置域名

1.要讲yaofeng.org域名解析到对应服务器的ip地址;2.在此过程中会提示为你自动设置https,但是需要你输入此域名拥有者的登记邮箱。

1
caddy -host yaofeng.org

看到

1
2
3
Activating privacy features... done.
https://yaofeng.org
http://yaofeng.org

表示https设置成功。

Caddyfile

为了方便配置,可以将所有的配置信息都写入Caddyfile文件
可以通过

"yaofeng.org" > Caddyfile```达到上述一样的效果。
1
在运行caddy命令时,也可以通过-conf参数设置对应Caddyfile配置文件的所在目录:```caddy -conf ../path/to/Caddyfile

也可以在一个Caddyfile中设置多个域名的解析

1
2
3
4
5
6
7
yaofeng.org {
root /www/yaofeng.org
}
sub.yaofeng.org {
root /www/sub.yaofeng.org
}

over

Fork me on GitHub