记浅析开源电商框架《flamingo-commerce》

简介

框架旨在构建电商系统的完整解决实现,通过DDD领域驱动设计,将抽象出来的具体领域模型实现,在核心域的基础上采用的六边形的设计思想,通过端口与适配器,实现灵活多变的电商架构体系

初识

开源地址:https://github.com/i-love-flamingo/flamingo-commerce

  1. 首先我们看看效果
    官方示例:https://demoshop.flamingo.me
    我部署的示例:http://www.itfan.top:3210
  2. 尝试自己部署
    提供了DEMO,地址:https://github.com/i-love-flamingo/commerce-demo-carotene
  3. 我部署的过程(略显坎坷)
    1. 踩过的坑:
      1. 首先我使用阿里云服务器(国内节点),搭建环境,包括golang、nodejs(当前最新版);部署的过程中发现版本不兼容,回退go(v1.13.6)、node(v12.16.3)
      2. 报错 Get https://accounts.google.com/.well-known/openid-configuration: dial tcp 172.217.27.141:443: i/o timeout 这里发现oauth认证使用的是google,我是国内的节点,无法访问,只能vpn解决了,借了mac,上了vpn一顿环境搭建,最后发现还是 timeout
      3. MAC部署,一样超时,浏览器访问google认证正常,查阅资料有说是google的秘钥认证失败后也不会给结果,同样是超时效果,然后去配了自己的秘钥,还是超时。最后发现mac终端是不走这个代理的,用了各种办法,无果;
      4. 直接上国外的节点,我的是香港的节点,20分钟搞定
      5. 总结,网络问题,奔溃
      6. 下列指令来自remark:
    # clone the repo:
    git clone https://github.com/i-love-flamingo/commerce-demo-      carotene.git
    cd commerce-demo-carotene
    # Download the test catalog  - you only need to do it once - it includes             products.csv and images:
    make download-product-data
    # Prepare translation files:
    make translation
    # Build the flamingo-carotene bases templates:
    make frontend-build
    # Run flamingo with flamingo-commerce
    make serve 
    
  4. 整体架构
    进入正题,项目采用前后端分离,各司其职,后端是基于commerce,
    commerce集成各个模块(模块边界采用DDD领域驱动设计思想),每个模块又基于flamingo框架进行具体的设计开发,系统间的交互采用了六边形的架构思想,通过端口与适配器达到一个可插拔的灵活性;首先我们看下flamingo框架做了什么事;

Flamingo框架特性

  1. 这里官网提供了demo 地址:git clone git@github.com:i-love-flamingo/example-helloworld.git

  2. 依赖注入(Dingo):用在端口 + 适配器、扩展点,上下文的准确映射

    injector.Bind().To();

  3. config:配置信息的读取、解析、映射封装

  4. even:事件的出发与监听

  5. session:支持多种存储(通过配置中心注入)


    image.png
  6. Healthcheck:系统指标监控

  7. router:路由规则(支持配置 + 代码)

    image.png

    image.png

  8. cache:响应数据、基础数据缓存


    image.png
  9. template:数据对view渲染,该框架集成了bug,通过


    image.png

    image.png
  10. SSO:支持单点登录


    image.png
  11. security:提供了功能权限、CSRF

  12. Logger trace :日志最终

  13. form ->controller : 通过将数据封装到FormHandlerFactory注入到控制层 获取数据

  14. GraphQL :自动生成,映射数据库,提供数据操作;

flamingo-commerce模块简绍

1.png
  1. 项目采用DDD(领域驱动设计)的设计思想,将整个电商业务领域分析和建模,划分为各个子领域,再将各个子域分层处理,提供了一套完整的默认电商实现

下面我们具体分析DDD在项目中如何落地的

  1. 整个电商系统是一个领域,项目业务将这整个领域细分为产品子域、客户子域、价格子域、订单子域、付款子域、结账子域、交货子域等,通过分析边界,定义了各个子域的界限上下文,通过分析与建模将各个子域领域模型抽象出来,通过DDD的分层思想,将各个领域服务分层
  2. 下面具体看下car项目的分层


    image.png
  1. application:包含了购物车的缓存、获取、修改操作,主要协调组织了业务的流程,当前模块与其模块比如:consumerService、userService进行一个交互
  2. domain:主要提现业务的概念、状态、规则,包含以下内容
    实体:Car;值对象:Address;聚合:Delivery;工厂:DeliveryInfoBuilder;
    car:其中包含了觉和信息,如Car(// Cart Value Object (immutable data - because the cartservice is responsible to return a cart).)是一个值对象,其中包含了对送货的操作、对购物车的操作、对总价计算操作,
    属性 + 行为
  3. infrastructure:提供了基于内存的购物车管理、email的集成
    这里可以重代码中看到框架的灵活
   func (m *Module) Inject(routerRegistry *web.RouterRegistry,config *struct {
    UseInMemoryCart bool `inject:"config:commerce.cart.useInMemoryCartServiceAdapters,optional"`
    EnableCartCache bool `inject:"config:commerce.cart.enableCartCache,optional"`
    UseEmailAdapter bool `inject:"config:commerce.cart.useEmailPlaceOrderAdapter,optional"`
},) {
m.routerRegistry = routerRegistry
if config != nil {
    m.useInMemoryCart = config.UseInMemoryCart
    m.enableCartCache = config.EnableCartCache
    m.useEmailAdapter = config.UseEmailAdapter
}
    if m.useInMemoryCart {
    injector.Bind((*infrastructure.CartStorage)(nil)).To(infrastructure.InMemoryCartStorage{}).AsEagerSingleton()
    injector.Bind((*infrastructure.GiftCardHandler)(nil)).To(infrastructure.DefaultGiftCardHandler{})
    injector.Bind((*infrastructure.VoucherHandler)(nil)).To(infrastructure.DefaultVoucherHandler{})
    injector.Bind((*cart.GuestCartService)(nil)).To(infrastructure.InMemoryGuestCartService{})
    injector.Bind((*cart.CustomerCartService)(nil)).To(infrastructure.InMemoryCustomerCartService{})
}

配置指定,通过依赖注入到容器,这里主要就是系统提了默认的数据存储方式,里面是数据的一个存储细节比如增、删、改、查

  1. interfaces:通过Form将请求数据封装,Controller接收后获取数据,并渲染前端页面;
    主要的逻辑 :
    1. 从*web.Request 中获取数据等一系列操作,底层看框架提供了通用的方法
    func (p *DeliveryFormService) GetFormData(ctx context.Context, req *web.Request) (interface{}, error)
    2. 注入service,并调用相应业务
    controller:func (cc *CartViewController) Inject(
    applicationCartService *application.CartService,
    applicationCartReceiverService *application.CartReceiverService,
    3. 在grgraphQL中提供查询统计方法
    func (cs CartSummary) SumGrandTotalWithGiftCards() *domain.Price {
    sum, err := cs.cart.SumGrandTotalWithGiftCards()
    if err != nil {
    return nil
    }
    return &sum
    }
  1. 总结,通过清晰的领域定义,我们可以很清晰的看到购物车模块的设计与每一层的作用,体会到DDD设计的可测试、可维护性、灵活性、可扩展性

在项目中六边形架构是如何落地实现的

  1. 首先总结六边形架构的优点
    优点:使用六边形架构开发的软件与通道独立,因此能支持多通道
    易于置换入站和出站整合点
    测试软件变得更简单,因为可以很容易地模拟集成点
  2. 通俗讲,该架构就是为了处理系统交互的,通过内部开通单端口,外部实现端口的适配器进行交互,这样我的核心服务不需要变动,可以支持多种协议或组件,做到灵活可插拔性,同时也为测试提供了方便
  3. 在项目中的实现
    cartServicePorts提供了端口,其中包括GuestCartService、CustomerCartService、ModifyBehaviour、、、等系列端口
    我们就拿GuestCartService端口来说,


    image.png

    这里是定义的一些借口方法,外部实现这些方法通过adapter,
    看下系统如何实现的


    image.png

    通过Adaptter 实现了对数据的内存储
  4. 总结上面的实现: 这里很清晰的感觉到,模块不会关心你的数据是如何存储的,我给你开了端口,你去实现,如何存储是外部的时,这样就可以兼容通道

总结

这里我主要介绍了项目的几个点,基础框架依赖flamingo,flamingo提供了通用域的实现比如配置、依赖注入、安全、缓存与前前端的一个模板渲染,在此基础上项目只需要关心业务,整个项目采用DDD(领域驱动设计)的架构思想,完成领域的拆分,各个模块依赖降到最低,通过对模块的分层,将各个层的职责单一化;同时结合六边形架构,解耦了模块间的依赖,通过端口 + 适配器的模式,实现多通道、多协议的支持,使项目扩展性更加强

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352