03
4

最近开始整理自己实际项目中用到的和可能用到的软件架构体系,我打算每种架构都好好写文章,并且根据自己的实际情况定制出相应的架构,我还希望把他编写成一个codesmith模板,可以实现自动化代码。前面7种是具体落地的软件架构,最后1种是架构设计思想。

1、极简数据库访问架构,这种架构非常适合编写一些小软件,里面只有一个SQLHelper文件,并且模仿三层架构,拥有DAL类和BLL类,最后加上一个程序入口Program。

2、简单三层架构,这种架构非常适合开发小型项目,web层就是MVC或者API,并且拥有BLL层和DAL层。

3、N层架构,这是一种适合大型项目的开发架构,但是更多是基于数据库构建的系统,没有基于DDD或者其他好的软件设计模式。

4、基于AutoFac、依赖注入和模板模式的多层架构。

5、基于ABP框架的架构,完全按照DDD设计模式开发,可能有些臃肿,但是非常适合大型软件和系统。

6、基于整洁架构的框架,完全按照DDD并且结合各种软件技术。

7、垂直切片架构,这是一种和传统分成架构完全不一样的架构,适合已经熟悉DDD和各种架构模式的成熟团队使用,并且适合开发微服务架构下的子系统。

8、基于清晰架构的微服务软件架构设计思想,这不是具体的实现,而只是一种架构大局观,用于指导大型的软件架构设计。

24
3

许多年前,我们开始了一个新的长期项目,首先,我们基于洋葱架构构建了它的架构。在几个月内,这种风格开始显示出裂缝,我们从这种架构转向CQRS。随着转向CQRS,我们开始围绕垂直切片而不是层(无论是平面还是同心,它仍然是层)构建我们的架构。从那以后,在过去7到8年左右的时间里,围绕垂直切片架构构建应用程序和系统的所有方式一直是我们独有的方法,我无法想象回到分层架构方法的限制。

传统的分层/洋葱/清洁架构在其目标是单体的:

这种架构方式问题是实际上只适用于系统中的少数典型请求。此外,我倾向于看到这些架构严重拟合,严格遵守依赖关系管理规则。在实践中,我发现这些规则很少有用,并且你开始得到很多关于真正不应该被抽象的抽象(控制器必须与必须使用存储库的服务进行对话)。

相反,我想对我的系统采用量身定制的方法,我将每个请求视为如何处理其代码的独特用例。因为我的系统整齐地分解为“命令”请求和“查询”请求(HTTP-land中的GET与POST / PUT / DELETE),所以向垂直切片架构的移动使我使用了CQRS。

什么是“垂直切片架构”?在这种风格中,我的架构是围绕不同的具体请求功能而构建的,通过这种方法,我们的每个垂直切片都可以自行决定如何最好地满足请求:

(对于获取订单,直接使用ORM转换为DTO,对于订单细节使用原生SQL转换为DTO,对于发票,使用基于聚合根的事件溯源,取消订单使用存储过程,这是一种微服务风格)

在所谓正常的“n层”或六边形或任何架构中,通过垂直切片移除这些层障碍,并沿着变化轴聚合在一起:

在应用程序中添加或更改功能时,通常会在应用程序中涉及到许多不同的“层”。现在改为沿着切片垂直将这些功能聚合在一起。

最小化切片之间的耦合,并最大化切片内的聚合。

通过这种方法,大多数抽象都消失了,我们不需要任何类型的“共享”层抽象,如存储库,服务,控制器。有时我们仍需要这些工具,但我们将交叉切片逻辑共享保持在最低限度。

通过这种方法,我们的每个垂直切片都可以自行决定如何最好地满足请求。

“企业架构模式”一书中的旧域逻辑模式不再需要成为应用程序范围内的选择。相反,我们可以从简单的(事务脚本)开始,并简单地重构从我们在业务逻辑中看到的代码气味中出现的模式。新功能只添加代码,您不会更改共享代码并担心副作用。非常自由!

但是,这种方法有一些缺点,因为它确实假设您的团队了解代码气味和重构。如果您的团队不理解“服务”在将逻辑推送到领域时自己却做得太多相关业务逻辑事情,那么这种模式可能不适合您。(服务类似餐厅服务员,服务员不应该做决定,只是协调者,当然如果你想退菜,服务员会决定说:不能退,菜已经烧了。)

如果您的团队确实理解了重构,并且能够识别何时将复杂的逻辑推入域,进入DDD服务应该是什么,并且熟悉其他Fowler/Kerievsky重构技术,那么您会发现这种架构风格能够远远超过传统的分层/同心架构。

来源:https://www.jdon.com/53095.html

24
3

这段时间一直在重构公司的项目代码,所以非常关注软件架构的设计,回顾我的架构接触史:第一次接触C#和.NET的时候就知道了三层架构和多层架构,当时被DAL和BLL等分层震惊了,原来软件设计还有那么多门道;毕业之后工作一直在使用多层架构,接着是MVC架构的出现,这种快速开发web站点的架构横扫整个行业;后来进入大厂工作,接触到了DDD;最近几年微服务架构又风声水起。

整体下来我最开始用了三层架构、然后是多层架构,接着是MVC架构配合多层架构,最后到了微服务架构,现在深刻理解那句话:没有最好的架构,只有最合适的架构。

网上看到有个人总结传统的架构演变之路:

三层架构:这是最简单、同时也是最成熟的软件应用程序架构,它将应用程序组织到三个逻辑和物理计算层中,包括表示层或用户界面、用于处理数据的应用(业务逻辑)程序层和用于存储和管理应用程序关联数据的数据层。大型项目中很少用,但是我还是会在一些小工具和小应用里运用。

多层架构:这种架构是三层架构的升级版,就是增加更多层对系统进行隔离,提高可扩展性和复用性,当然也增加了系统的复杂度。这是我刚毕业那家年用得最多的架构。

基于DDD的分层架构:采用领域驱动设计的思想设计的多层架构,以领域模型为核心、使用依赖注入和控制反转等技术来实现软件,对系统进行解耦,获得最大限度地可维护性和可扩展性。这是我现在在项目中用得最多的架构。

领域模型准确反映了业务语言,而传统数据对象除了简单setter/getter方法外,没有任何业务方法,即失血模型,那么DDD领域模型就是充血模型(业务方法定义在实体对象中)。首次清晰描述了领域驱动的分层实现并统一了业务语言。单一职责、低耦合、高内聚、业务内核沉淀。

六边形架构:让用户、程序、自动化测试和批处理脚本可以平等地驱动应用,让应用的开发和测试可以独立于其最终运行的设备和数据库。

左侧: 代表 UI 的适配器被称为主适配器,它们发起了对应用的一些操作,端口(应用层API)和它的具体实现(controller实现)都在应用内部。右侧: 表示和后端工具链接的适配器,被称为从适配器,它们只会对主适配器的操作作出响应,端口在应用内部(业务接口),具体实现(impl)在应用之外。

洋葱架构:在端口和适配器架构的基础上贯彻了将领域放在应用中心,将传达机制(UI)和系统使用的基础设施(ORM、搜索引擎、第三方 API...)放在外围的思路。洋葱架构在业务逻辑中加入了一些在“领域驱动设计”中被识别出来的层次。

围绕独立的对象模型构建应用。内层定义接口,外层实现接口。依赖的方向指向圆心。所有的应用代码可以独立于基础设施编译和运行。职责分离更彻底,高内聚低耦合。更好的可测试性和可维护性。

整洁架构:这套架构是站在巨人的肩膀上,把MVC、EBI、端口适配器、洋葱架构、DDD融会贯通,形成了一套落地实践方案。

清晰架构:融合 DDD、洋葱架构、整洁架构、CQRS等一系列架构的信息,这种架构很复杂,你可以根据实际情况来选择。

微服务架构:微服务架构的诞生是因为docker的兴起,因为可以更好地管理各种部署,所以可以将一个大型系统拆分部署到docker之中,每个小服务都能实现集群部署。我个人认为并非一开始就要上微服务架构,架构是不断演化的过程,哪怕是一开始就定位很大系统,可以先划分出基本的服务就行(比如登录系统、支付中心、内容服务、接口开放平台和后台系统),更细的划分可以随着业务的发展不断演化——当然前提是要一直保证代码的整洁和简洁、遵循基本的面向对象代码原则。

垂直切片架构:我是最近才接触到了这种架构,我们的项目最近用到了MediatR和AutoMapper,这两个开源项目的作者Bogard JIMMY BOGARD在自己的项目中实现了这种架构,通过反思洋葱架构和整洁架构等各种分层和抽象得出来的一种架构,作者不建议做太多的分层,因为各种以来会导致大量的问题,作者认为在微服务架构里面特别实用,当然代码也会准从DDD的设计原则。作者认为在所谓传统正常的“N层”或六边形或任何架构中,通过垂直切片移除这些层障碍,并沿着变化轴聚合在一起:

02
4

最近公司的移动开发工程师被困在老家,项目有紧急需要修改的地方,我只好亲自上阵,打开Xcode改bug。编译的过程发现小伙子前阵子刚刚升级了,遇到了c++头文件无法编译的问题。网上查了一下,发现这是Xcode的通病,三个版本都有类似的问题。

Xcode10 'string' file not found C++头文件缺失问题

将对应文件拷贝到Xcode10对应目录下

真机: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/c++
模拟器:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/c++

Xcode9 C++头文件github链接:https://github.com/DeCori/Xcode9-cpp.git

Xcode10中缺少的libstdc++6.0.9.tbd库
其中文件夹 1、2、3、4 中的文件分别对应复制到Xcode10中的以下4个目录中即可:

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/

/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/lib/

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/lib/

Xcode11和12文件的1路径发生改变:

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib
22
10

前两天为了研究隐形数字水印技术,了解了一些OpenCV的用法,涉及到把黑色背景图去掉的方法,别的不多说,直接上代码吧!

import os
import cv2

path = "D:/build/utensilspictureNew" #文件夹目录

# 遍历文件夹及其子文件夹中的文件,并存储在一个列表中
# 输入文件夹路径、空文件列表[]
# 返回 文件列表Filelist,包含文件名(完整路径)
def get_filelist(dir):
    newDir = dir
    if os.path.isfile(dir):
        src  = cv2.imread(newDir,1)
        tmp = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
        _, alpha = cv2.threshold(tmp, 0, 255, cv2.THRESH_BINARY)
        b, g, r = cv2.split(src)
        rgba = [b, g, r, alpha]
        dst = cv2.merge(rgba, 4)
        cv2.imwrite(newDir, dst)
        print('Done');
    elif os.path.isdir(dir):
        for s in os.listdir(dir):
            newDir=os.path.join(dir,s)
            get_filelist(newDir)

get_filelist(path)

代码还包括了如何递归遍历文件夹里的文件夹和文件。

18
10

隐形数字水印技术

0
归档:2021年10月分类:架构之路

这两天需要给项目中的图片加水印,考虑到美观就放弃了显性的水印,而采用隐形的数字水印。利用数字水印的不可见性,在不影响作品的情况下,加入版权信息的数字水印,可抗击拷贝,剪切。

数字水印(DigitalWatermarking)技术是将一些标识信息(即数字水印)直接嵌入数字载体(包括多媒体、文档、软件等)当中,但不影响原载体的使用价值,也不容易被人的知觉系统(如视觉或听觉系统)觉察或注意到,只有通过专用的检测器或阅读器才能提取。数字水印是一个崭新的信息隐藏技术,首次提出这个概念至今也不到20年。

我采用的是github上面的一个开源库blind_watermark (https://github.com/guofei9987/blind_watermark)

这是基于小波变换的数字盲水印,用python来写的,效果还可以,不过通过通信软件截图或者发送之后,就无法获取到数字水印了,这个只能防那些直接拿来使用的盗用者。

另外,如果图片上透明背景的png格式,转换之后会生成黑色底色,这个也很不好,我花了两天时间试图修改源码,还是没有完成。

虽然没有能,但是学会了一些OpenCV的技术。

15
10

用python给图片添加半透明水印

0
归档:2021年10月分类:架构之路

我一直都是用C#来完成水印的生产,最近捣腾python脚本,查了一下,可以很方便地用python给图片添加半透明水印。

# coding:utf-8

from PIL import Image, ImageDraw, ImageFont

def add_text_to_image(image, text):
    font = ImageFont.truetype('C:\Windows\Fonts\STXINGKA.TTF', 36) # 获取字体

    # 添加背景
    new_img = Image.new('RGBA', (image.size[0] * 3, image.size[1] * 3), (0, 0, 0, 0))
    new_img.paste(image, image.size)

    # 添加水印
    font_len = len(text)
    rgba_image = new_img.convert('RGBA')
    text_overlay = Image.new('RGBA', rgba_image.size, (255, 255, 255, 0))
    image_draw = ImageDraw.Draw(text_overlay)

    for i in range(0, rgba_image.size[0], font_len*40+100):
        for j in range(0, rgba_image.size[1], 200):
            image_draw.text((i, j), text, font=font, fill=(0, 0, 0, 50))
    text_overlay = text_overlay.rotate(-45)
    image_with_text = Image.alpha_composite(rgba_image, text_overlay)

    # 裁切图片
    image_with_text = image_with_text.crop((image.size[0], image.size[1], image.size[0] * 2, image.size[1] * 2))
    return image_with_text

if __name__ == '__main__':
    img = Image.open("test.jpg")
    im_after = add_text_to_image(img, u'test_output')
    im_after.save(u'test_output.png')
15
3

前言

去年公司已经完成所有产品的.NET Core改造工作,团队成员也逐步积累了docker和devops的知识,今年的主要任务之一就是把核心的产品迁移到devops生产线上。本来是打算用微软的Azure平台,因为真的太好用了,我自己的测试站点就一直用Azure来做持续交付工作。但是公司原来的产品、数据、备案都在阿里云上,迁移的话会有大量的工作,包括数据迁移、备案迁移都很麻烦。加上目前国内这种政治绝对正确的要求,搞不准哪天就因为用Azure就撞雷了,虽然很无语,但是也没有办法。

这几天一直在想方案,前年是打算用开源的持续集成(CI)工具Jenkins来配合阿里云,不过去年发现GitHub Action用起来更加顺畅,而我们的代码基本都是托管在GitHub上面,阿里云去年也发布了自己的K8S平台ACK,我们打算当小白鼠,正式使用看看效果如何。

不过在使用ACK之前,我们希望能够把Github上面的代码持续发布到docker Hub上面,去年已经完成了这部分工作,今天整理一下步骤和流程。

一、创建docker Hub账号

首先是到 https://hub.docker.com/ 创建一个账号,并且创建一个自己的repository,可以是公开的,也可以是私有的。另外,设置和GitHub的连接:
file

二、创建Dockerfile

通过VSCode或者VS创建自动Dockerfile,如果是VS,就右键项目(不是解决方案),添加Docker支持,VS会自动生成这个项目的Dockerfile文件,不用做任何修改。
file

三、提交整个解决方案

我们的项目一般都是位于一个解决方案里面,所以一个解决方案可能保护多个项目,这个没有问题,把整个解决方案都提交到GitHub上面,当然必须是本地可以编译通过并且可以运行的代码。网上很多教程都没有说清楚这种项目的打包细节,我后面会重点说一下,因为对于一个初学者,很容易在这里迷茫。

四、设置GitHub的密钥

需要把第一步创建的Hub账号填写到GitHub的settings里面:
file

五、编写Action的WorkFlow

通过Github的Action,可以创建很多类型的工作流WorkFlow,非常方便。
file
可以看到,几乎涵盖了所有国内外常用云平台的模板。
file
当然了,也包含了几乎所有常用开发语言的模板,太牛了。

Github上还有非常多通用的Action,你可以直接引用来使用,这里我不多说,贴一个我们可以运行的WorkFlow:

name: .NET

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
 docker:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Setup .NET Core
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 3.1.x
    - name: Push to Docker Hub
      uses: docker/build-push-action@v1
      with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
          dockerfile: ./Academy.PCCore/Dockerfile
          repository: academy/academypc
          tags: v0.0.1
          tag_with_ref: true

这里重点说一下后面的这几个变量:
1、username和password就是第四步里面设置的变量。
2、dockerfile的路径问题,路径“./”就是指当前在Github的这个respository的根目录,比如:
file
这里我只需要将Academy.PCCore项目打成docker,Dockerfile也在这个文件夹的根目录。
3、repository,这个就是在Docker Hub里面创建的仓储Respository的路径,两边一定要一直,否则无法提交。

这里我使用了三个别人写好的Action, actions/checkout@v2 是迁出代码到GitHub运行环境的Action,actions/setup-dotnet@v1 是生成打包.NET Core程序的Action,docker/build-push-action@v1 将程序打包到Docker并且发布到Hub的Action,自己几乎不用写太多代码,确实非常方便。

公告栏

欢迎大家来到我的博客,我是dodoro,希望我的博客能给你带来帮助。