关于软件的架构:微服务架构、清晰架构、整洁架构、洋葱架构、六边形架构、垂直切片架构、基于DDD分层架构、三层架构

这段时间一直在重构公司的项目代码,所以非常关注软件架构的设计,回顾我的架构接触史:第一次接触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层”或六边形或任何架构中,通过垂直切片移除这些层障碍,并沿着变化轴聚合在一起:

March 24, 2023

解决Xcode 10 、Xcode11、Xcode12升级之后 'string' file not found C++头文件、`libstdc++6.0.9.tbd`库缺失问题

最近公司的移动开发工程师被困在老家,项目有紧急需要修改的地方,我只好亲自上阵,打开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

April 2, 2022

使用python的opencv库来移除黑色背景图

前两天为了研究隐形数字水印技术,了解了一些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) 代码还包括了如何递归遍历文件夹里的文件夹和文件。

October 22, 2021

隐形数字水印技术

这两天需要给项目中的图片加水印,考虑到美观就放弃了显性的水印,而采用隐形的数字水印。利用数字水印的不可见性,在不影响作品的情况下,加入版权信息的数字水印,可抗击拷贝,剪切。 数字水印(DigitalWatermarking)技术是将一些标识信息(即数字水印)直接嵌入数字载体(包括多媒体、文档、软件等)当中,但不影响原载体的使用价值,也不容易被人的知觉系统(如视觉或听觉系统)觉察或注意到,只有通过专用的检测器或阅读器才能提取。数字水印是一个崭新的信息隐藏技术,首次提出这个概念至今也不到20年。 我采用的是github上面的一个开源库blind_watermark (https://github.com/guofei9987/blind_watermark) 这是基于小波变换的数字盲水印,用python来写的,效果还可以,不过通过通信软件截图或者发送之后,就无法获取到数字水印了,这个只能防那些直接拿来使用的盗用者。 另外,如果图片上透明背景的png格式,转换之后会生成黑色底色,这个也很不好,我花了两天时间试图修改源码,还是没有完成。 虽然没有能,但是学会了一些OpenCV的技术。

October 18, 2021

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

我一直都是用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')

October 15, 2021

使用Github Action将.NET Core发布到docker Hub

前言 去年公司已经完成所有产品的.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的连接: 二、创建Dockerfile 通过VSCode或者VS创建自动Dockerfile,如果是VS,就右键项目(不是解决方案),添加Docker支持,VS会自动生成这个项目的Dockerfile文件,不用做任何修改。 三、提交整个解决方案 我们的项目一般都是位于一个解决方案里面,所以一个解决方案可能保护多个项目,这个没有问题,把整个解决方案都提交到GitHub上面,当然必须是本地可以编译通过并且可以运行的代码。网上很多教程都没有说清楚这种项目的打包细节,我后面会重点说一下,因为对于一个初学者,很容易在这里迷茫。 四、设置GitHub的密钥 需要把第一步创建的Hub账号填写到GitHub的settings里面: 五、编写Action的WorkFlow 通过Github的Action,可以创建很多类型的工作流WorkFlow,非常方便。 可以看到,几乎涵盖了所有国内外常用云平台的模板。 当然了,也包含了几乎所有常用开发语言的模板,太牛了。 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的根目录,比如: 这里我只需要将Academy.PCCore项目打成docker,Dockerfile也在这个文件夹的根目录。 3、repository,这个就是在Docker Hub里面创建的仓储Respository的路径,两边一定要一直,否则无法提交。 ...

March 15, 2021

【转】插画版Kubernetes指南

插画版Kubernetes指南(小孩子也能看懂的kubernetes教程) 是根据一个视频翻译过来的,比较形象 编者按:Matt Butcher 是 Deis 的平台架构师,热爱哲学,咖啡和精雕细琢的代码。有一天女儿走进书房问他什么是 Kubernetes,于是就有了这本插画版的 Kubernetes 指南,讲述了勇敢的 Phippy(一个 PHP 应用),在 Kubernetes 的冒险故事,满满的父爱有木有! 某一天 有一天,女儿走进书房问我:『亲爱的爸爸,什么是 Kubernetes 呢?』 我回答她:『Kubernetes 是一个开源的 Docker 容器编排系统,它可以调度计算集群的节点,动态管理上面的作业,保证它们按用户期望的状态运行。通过使用「labels」和「pods」的概念,Kubernetes 将应用按逻辑单元进行分组,方便管理和服务发现。』 女儿更疑惑了……于是就有了这个故事。 给孩子的插画版 Kubernetes 指南 很久很久以前,有一个叫 Phippy 的 PHP 应用,她很单纯,只有一个页面。她住在一个托管服务里,周围还有很多可怕的应用,她都不认识,也不想去认识,但是他们却要共享这里的环境。所以,她一直都希能有一个属于自己的环境:一个可以称作 home 的 webserver。 每个应用的运行都要依赖一个环境,对于一个 PHP 应用来说,这个环境包括了一个 webserver,一个可读的文件系统和 PHP 的 engine。 有一天,一只可爱的鲸鱼拜访了 Phippy,他建议 Phippy 住在容器里。Phippy 听从了鲸鱼的建议搬家了,虽然这个容器看起来很好,但是……怎么说呢,就像是漂浮在海上的一个小房间一样,还是没有家的感觉。 不过容器倒是为应用提供了隔离的环境,在这个环境里应用就能运行起来。但是这些相互隔离的容器需要管理,也需要跟外面的世界沟通。共享的文件系统,网络,调度,负载均衡和资源分配都是挑战。 『抱歉……孩子……』鲸鱼耸耸肩,一摇尾消失在了海平面下…… Phippy 还没有来得及失望,就看到远方驶来一艘巨轮,掌舵的老船长非常威风。这艘船乍一看就是大了点,等到船走近了,Phippy 才发现船体两边挂满了皮筏。 老船长用充满智慧的语气对 Phippy 说:『你好,我是 Kube 船长』。 『Kubernetes』是希腊语中的船长,后来的『Cybernetic』和『Gubernatorial』这两个词就是从 Kubernetes 衍生来的。Kubernetes 项目由 Google 发起,旨在为生产环境中成千上万的容器,构建一个健壮的平台。 ...

June 2, 2020

【转】.NET Core微服务之ASP.NET Core on Docker

原作:Edison Zhou 恰童鞋骚年 一、Docker极简介绍 1.1 总体介绍 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。 简而言之> 容器是一个打包了应用服务的环境,它是一个轻量级的虚拟机,每一个容器由一组特定的应用和必要的依赖库组成。 Docker和传统虚拟化之间最大的区别在于:容器是在操作系统层面上实现虚拟化,即直接复用本地主机的操作系统;而传统虚拟化则是在硬件层面实现,如VMware vShpere, Xen及Citrix等。 1.2 Docker结构 Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。 Docker 容器通过 Docker 镜像来创建。 容器与镜像的关系类似于面向对象编程中的对象与类。 Docker的架构如下图所示,Client 通过接口与Server进程通信实现容器的构建,运行和发布。Client和Server可以运行在同一台集群,也可以通过跨主机实现远程通信。 具体详细内容,请浏览:《几张图帮你理解Docker基本原理及快速入门》 二、Docker的安装 (1)准备一台Linux主机,这里以CentOS 7.2为例。当然,你也可以使用Windows,不过你得确保是Windows 10 pro版本及以上,且安装了Hyper-V等一系列的相关软件。 (2)安装docker # yum install docker (3)启动docker服务 # systemctl start docker.sevice (4)配置开机启动并验证 # systemctl enable docker.service 验证:查看docker版本信息 # docker version (5)配置docker加速器 => 原因你懂得,不设置慢死你,云服务器除外 # vim /etc/docker/daemon.json { “registry-mirrors”: ["https://d8b3zdiw.mirror.aliyuncs.com"] } 然后重启docker服务 # systemctl daemon-reload ...

June 1, 2020

选择Angular而不是Vue

最近团队要选择前端开发框架,我进行了大量对比,最终选择了Angular,我承认Vue也很优秀,React也超级棒,但Angular非常适合我们。我们需要的就是这样一个真正的框架,包含了组件化方案、模块化方案、测试方案、表单验证、路由、国际化方案和安全方案。 Angular 的工程师将我们需要的所有功能做了不错的整合。如果使用 Vue,我可能还要面临更多选择。Angular 的一份文档涵盖了开发中的方方面面。如果使用 Vue,可能每个功能要去看不同的文档。Angular 更强势更主观,它的文档对于如何完成某个功能给出了明确的建议。我们团队的成员有不同的编程背景,虽然有三个全职的前端,但是还有十几个 Java 和 Python 程序员,他们也可能会参与前端工作,Angular 的文档能让这些成员快速适应环境。 Angular = Vue + vue-router + axios + karma + 表单验证插件 + i18n … 我们需要typescript来告别原来脓肿不堪的js代码 使用TypeScript,告别对臃肿代码的重构,让自己的编程真正能够面向对象吧。 一千个人有一千种React代码风格,但是Angular的代码风格只有一种。你会发现Angular的每一处都是最佳实践,设计模式的运用是基于Google多年的Java编程经验的,响应式的应用也是基于微软对于操作系统中异步处理的经验总结。 无数的编程概念都有其历史厚重感,而Angular将他们汇聚到了一起。windows中的linq‘时间上的数组’,spring中的依赖注入,处理HDFS的MR,到linux线程本地存储,再到前端界的MVVM,MVC。 Angular优势: Angular 的工程师将我们需要的所有功能做了不错的整合。如果使用 Vue,我可能还要面临更多选择。 Angular 的一份文档涵盖了开发中的方方面面。如果使用 Vue,可能每个功能要去看不同的文档。 Angular 更强势更主观,它的文档对于如何完成某个功能给出了明确的建议。我们团队的成员有不同的编程背景,虽然有三个全职的前端,但是还有十几个 Java 和 Python 程序员,他们也可能会参与前端工作,Angular 的文档能让这些成员快速适应环境。 核心原因:Angular 是一个完整的框架。

June 10, 2019

CentOS编译安装shadowsocks-libev

部署环境:CentOS 7.4 x64 shadowsocks-libev项目地址 编译安装 yum update -y yum install -y epel-release rng-tools yum install -y git wget gettext gcc autoconf libtool automake make asciidoc xmlto c-ares-devel libev-devel zlib-devel openssl-devel rngd -r /dev/urandom 安装Libsodium export LIBSODIUM_VER=1.0.16 wget https://download.libsodium.org/libsodium/releases/libsodium-$LIBSODIUM_VER.tar.gz tar xvf libsodium-$LIBSODIUM_VER.tar.gz pushd libsodium-$LIBSODIUM_VER ./configure --prefix=/usr && make make install popd ldconfig 安装MbedTLS export MBEDTLS_VER=2.7.0 wget https://tls.mbed.org/download/mbedtls-$MBEDTLS_VER-gpl.tgz tar xvf mbedtls-$MBEDTLS_VER-gpl.tgz pushd mbedtls-$MBEDTLS_VER make SHARED=1 CFLAGS=-fPIC make DESTDIR=/usr install popd ldconfig 安装shadowsocks git clone https://github.com/shadowsocks/shadowsocks-libev.git cd shadowsocks-libev git submodule update --init --recursive ./autogen.sh && ./configure && make make install cd .. 修改配置 mkdir /etc/shadowsocks-libev vi /etc/shadowsocks-libev/config.json 写入以下内容并保存 ...

June 4, 2019