今天小黑力气有所恢复。大部分时候趴着睡觉。。 中午能坐立进食。饭量较昨日有所增加。干粮吃了一小盘。有尿,无拉屎。
Archiv des Autors: chenhongyi
重装El Captian
由于系统盘损坏,需要要重装El Captian. 关键是如何制作一个启动U盘
教程在此
mkdir -p /mnt/OSX_InstallESD /mnt/OSX_BaseSystem /mnt/usbstick
# convert installer disk image to raw format
dmg2img "Install OS X .app/Contents/SharedSupport/InstallESD.dmg" InstallESD.img
kpartx -a InstallESD.img
mount /dev/mapper/loop0p2 /mnt/OSX_InstallESD
# convert base system disk image to raw format
dmg2img /mnt/OSX_InstallESD/BaseSystem.dmg BaseSystem.img
kpartx -a BaseSystem.img
mount /dev/mapper/loop1p1 /mnt/OSX_BaseSystem
# partition the USB flash drive, /dev/sdX
sgdisk -o /dev/sdX
sgdisk -n 1:0:0 -t 1:AF00 -c 1:"disk image" -A 1:set:2 /dev/sdX
mkfs.hfsplus -v "OS X Base System" /dev/sdX1
mount /dev/sdX1 /mnt/usbstick
# copy installer files
rsync -aAEHW /mnt/OSX_BaseSystem/ /mnt/usbstick/
rm -f /mnt/usbstick/System/Installation/Packages
rsync -aAEHW /mnt/OSX_InstallESD/Packages /mnt/usbstick/System/Installation/
rsync -aAEHW /mnt/OSX_InstallESD/BaseSystem.chunklist /mnt/usbstick/
rsync -aAEHW /mnt/OSX_InstallESD/BaseSystem.dmg /mnt/usbstick/
sync
出处 https://askubuntu.com/questions/743075/how-to-make-a-bootable-osx-el-capitan-usb
然后需要一块能点亮的启动A卡。原装的我拆下了,还好没丢,重新装上引导系统的选择从U盘启动。
其他启动的按键组合可以参考这里: https://www.makeuseof.com/tag/boot-mode-startup-keys-mac/
然后需要转一些必要的软件,比如chromim浏览器,plex 都是一些需要特别老的版本。 好在有github都能找到。
初识DDD 之CQRS
最近在学习实践DDD,接触到一个新的概念CQRS。以前以为就是读写分离,是基础设施层数据库层面的事情。学习以后才发现,并不只是这样,更应该是App应用层面的事。
缘起从github上找了一个DDD的symfony的例子,想参考一下,用于重构目前的项目。看了介绍和代码以后,发现了他的作者的西班牙语的油管视频。结合自动字幕翻译,觉得还不错,然后看了一下他们写的书。原版要60欧,于是在github上下载了一本电子版 Domian Driven Desgin in PHP。以下是阅读的笔记。
MVC模式的缺点
MVC用了那么久了,最大问题是controller过于庞大。违反了分离原则(Separation of Concerns)。补救的办法是使用依赖倒置。由于controller包含了过多的领域内容。所以首先拿领域模型下手。很多领域模型依赖底层的基础架构,比如数据库。所以按照Bob大叔(Robert C. Martin)的依赖倒置原则,高级模块(领域)不该依赖低级模块(基础设施),而且应该让它依赖抽象,即提出Repository。然后六角形架构被提出了。所有才有后来的 CQRS 和 Event Sourcing 。
初识DDD 之CQRS
写模 型 Write model.
也叫Command model, 1
被改造为基于事件的写模型。本来直接写入数据库动作,改为发布一个写入事件。
record -> apply -> publish
而且写入事件直接找领域模型里定义。
读模型 Read model
被简化为从ElasticSerach这样的缓存读取。
同步
即然读写分开了,那么两个模型如何实现同步呢。引入了新概念Projection (投射器?)。基本上就是监听事件。当符合的事件被监听到了,就会调用投射器的投射动作。
投射的过程很可能是异步的,就是说会有延迟。为了解决延迟,在Repo里的save方法内,创建一个transaction(过程),把存储,事件放在一起。然后用投射器投射保存的事件。
最终解决了读模型和写模型之间的一致性(consistencies)问题。
Evnet Sourcing 事件溯源
就是可以通过记录完整的event可以还原一个状态。有点像数据库的bin log。
Code Review 收获
今天请Ben对项目的重构Branch进行了Review。收获是很多的。
传入参数和返回值,尽量使用Interface
当使用match分支处理情况的时候,也要和switch类似,加上处理默认default的情况
避免使用动态生成的方法和类
动态的方法和类就是指名称包含变量的。比如
setFirstName(), setLastName()
这样的方法,为了偷懒,我使用set加上一个变量的名字的方法,比如 set$var()
这样的方法或者类不利于静态检查,应该避免使用。
Domain领域应该和外界尽可能的隔绝。
Domain内不该知道什么是REST,DB,gRPC等具体实现的技术概念
应该只使用传入的Interface的公开方法
简化复杂的DI的声明
使用静态分析工具 PhpStan
使用docker volumn共享卷以及同步
启动的时候,报错,说一个卷没有。需要手动创建。然后在docker compose里面看到,在多个容器中都使用了一个卷名。命令行中有提示,如何手动创建一个卷。
尝试创建后发现是空的,再看它还有一个docker-sync配置。然后安装docker-sync工具。制定后启动,然后它就留在后台运行了。
再启动容积,这次卷就被挂上了。
docker volume 命令
docker-sync 工具
„%“ or „@“ in symfony config yml file
比较一下
$isEnableAborting: '%checkout.coupon.aborting.enabled%'
和
$isEnableAborting: '@checkout.coupon.aborting.enabled'
据我所知, @是应用服务的id,%用来包裹应用定义的变量
分析feature toggle类
项目中有些功能,只在特定调价下可供使用。所以Ben写了一个feature toggle类。故名思义就是提供功能切换的类。
背景需求
1 需要按照storefront来实现功能的开关
2 对于没有通过storefront的,还可以通过一个optimizely进行开关
首先实现了一个上下文对象,context。context里包括了 userid 和 storefront。
然后定义了一个toggle接口。只含有一个enable方法。然后实现了3个具体的toggle类。他们是
- optimzly
- storfont
- oneof
配置里,使用oneof来注入到service中。oneof的构造函数接受一组(迭代器)toggles。当他被询问enable的时候,它会逐个询问它的迭代器里的每个toggle。只要有一个返回true,它就返回true。所以名字叫做oneof。
配置oneof的时候,给他配置2个toggle。一个是storefront_de。一个是optimzley。
然后在storefornt_de只配置里storefront
optimizley 是依赖外部的optimizely服务的。所以配置需要一个key和客户端。
整个实现结构清晰。明确。非常赞。
在Symfony中如何获取所有的message handler
在测试的时候,需要获取symfony的里所有的的message handler,该如何做到呢?
通过 messenger.message_hanlder 就可以。
比如你的测试需要测试所有的 message handler
1 在容器中注册一个provider ,比如 MessengerHanlderProvider
App\Tests\Functional\StaticCodeAnalysis\MessengerHandlerProvider:
public: true
arguments:
$handlers: !tagged_iterator messenger.message_handler
2 然后实现该provider类 class App\Tests\Functional\StaticCodeAnalysis\MessengerHandlerProvider ,它只有一个作用,就是接受一个返回所有handler迭代器,它的构造函数的为 !tagged_iterator messenger.message_handler。
public function __construct(iterable $handlers)
{
$this->handlers = iterator_to_array($handlers);
}
意思就是返回给我所有的tag标记部位MessageHandler的类。因为我们在用Messenger定义消息的hanlder的时候,都按照教程,给每个定义为hanlder的类加上这个标签。比如:
#[AsMessageHandler]
readonly class FinalizeCancellationsHandler
{... }
#[AsMessageHandler]
class SyncCancellationsHandler
{...}
这样就可以轻松获取所有的messenger 的handler了。
3 在测试中需要用到返回所有消息handler的时候,只要问容器去要就可以了。比如
static::getContainer()->get(MessengerHandlerProvider::class);
相关视频教程
docker build超时的时候调整compose 的timeout全局设置
当遇到timeout,不能完成下载的时候,可以调高timeout的设置。
$ export COMPOSE_HTTP_TIMEOUT=600
源 https://github.com/docker/compose/issues/3851