这个不是单元测试吧,这个算是集成测试了,需要在独立的测试进程中对其进行测试,就好像是应用程序的真实使用者一样。
对于单元测试,如果测试的目标依赖了一个外部的组件,常用的做法是对这种外部组件进行 Mock ,比如测试目标需要一个发送消息的服务( MessagePublisher ),可以 Mock 一个消息发送服务( InMemoryMessagePublisher ),然后对测试目标进行测试,并观察 InMemoryMessagePublisher 中的结果是否符合预期,当然这只是一个很简单的例子,因为单元测试足够小,所以可以反复快速的完成测试内容。
测试是一个很复杂的概念,每个人或者组织都有不同的偏好,在我看来归根结底无非就是两个问题,那就是搞清楚我们到底在测试什么?我们期望测试将来可以起到什么帮助?
        
     
    
    
    
        @
bk201 我用的是添可的洗地机(芙万 2.0 ),型号差异感觉并不是很大,主要是清理方便。
 
    
    
    
        Ioc 的主要作用就是读取组件声明( XML/注解 /代码注册),也就是构造 IoC ,然后实例化和管理这些组件的生命周期。
根据构造组件所需要的定义(面向对象语言中通常是 class 的构造函数),就可以得到创建这些组件所需要的先后顺序,从而不必手动去硬编码这个过程。
另外 IoC 本身的生命周期(创建 /销毁)形成了一个 scope 作用域,从而可以管理存在于容器内的各种实例。
所以一般 IoC 有两个阶段,一个阶段是读取声明(注册组件,构造 IoC ),另一个阶段是构造和管理组件。
对于非面向对象的语言,我能想到的就是在读取组件定义这一块(即对应面向对象中 class 的构造函数),转变为了一个 Key 和包含回调函数的 struct 。
这个 key 可能就是一个简单的字符串,类似 map 或者 dict 中的 Key 。
这个 struct 由 IoC 定义,里面包含了初始化定义(依赖描述),生命周期回调函数(函数签名由 IoC 定义),以及一个指向实际值的 interface{}指针。
上面说到 IoC 本身也是有生命周期的,它提供了一种作用域的语义,因此可以很方便的管理一系列组件的实例。
另外说一下 SpringBoot 的各种 starter 也只是提供了一个默认的组装布局,或者称之为开箱即用的默认配置,只不过可以根据配置文件来自动进行组装逻辑,这就需要提供一种通用的描述规范。
        
     
    
    
    
        洗地机很好用,我是一点容不得地上有什么污渍的,比如有一根毛发也要用纸把他给清理掉,可能是有点强迫症,甚至在吃饭的时候会时不时扭头绕着身子观察地面上有没有什么东西,这个毛病怎么也改不了。
        
     
    
    
    
        没明白你说的对用户不友好是啥意思,往一个已经删除的关联数据增加新的数据,按理说应该失败并告知原因,例如不存在 menu ,除此之外还能怎么做呢?可以吞掉这个错误,就当请求没发生,或者正常插入脏数据?
数据已被删除是一个事实,优化的方案也可以当有用户编辑 menu 的时候不允许删除,这取决于想要的逻辑是什么。
回到正题,解决这个并发问题最简单的方法就是使用乐观锁,或者直接使用独占锁( SELECT ... FOR UPDATE )。如果是独占锁,当你在进行操作的时候(新增 content ),别人是没办法查询或者修改这个 menu 的。当完成操作,另一个试图删除 menu 的时候,走正常的删除逻辑。
        
     
    
    
    
        我家里的 K2P 一样的,桥接拨号刚开始可以达到 50MB 的下载速度( 500M 宽带),过一段时间以后就基本上 20MB 左右( 5G ),之前查过好像要刷系统开启什么功能,不过我一年很少在家,也懒得去搞了,下次回去准备把路由器换了。
        
     
    
    
    
    
    
    
        给微服务一个定义吧,普遍认为的微服务就是把什么订单、用户等等系统拆分出来当作一个独立的项目来开发和部署,但是需要注意这个“拆分”只是逻辑上的。
比如我在开发的时候将所有的服务都放在一个项目里面,然后最终只打包出一个可执行文件来,分别在 ABC 机器上面进行部署,然后在 nginx 上面针对请求的 URL 路径转发到不同的机器上。我可以在 ABC 机器上面都分别配置不同数据库,毕竟这台机器只负责部分子集,只会操作部分的数据表,这样一来出现的一个问题就是 ABC 之间数据不互通了,比如订单需要查询用户信息,调用 UserService ,UserService 将不会查询到用户数据,因为这些数据存在于另一台机器和另一个数据库上,一种办法是 ABC 三台机器使用同一个数据库,这样可以解决数据互通的问题。注意自始至终我没有使用到 RPC 以及消息队列,我只是将同一个程序部署到了三台机器上,每一个机器负责部分的 URL 请求,你说这算不算是微服务呢?
如果你认为不算,我们可以改造一下,当某一个机器调用 XXXService.doSomething()的时候,实现不再是通过 JVM 进程内直接调用对象方法,而是通过构造 HTTP 请求另外一台专门负责这服务的机器来进行处理,这样一来,我们就可以将 ABC 三台机器又恢复到使用各自独立的数据库。如果我们拆分得足够好,三台机器应该至始至终只会生产和查询自己负责的那几张表。你说这算不算是一种微服务呢?
注意不管我如何部署,我们的开发结构仍然是一个单体的大项目,所有的代码在变更以后都需要重新打包然后部署到三台机器上面,但是如果我只修改了 A 机器负责的功能,我可以只更新 A 机器那一份,只要接口没有变动,其他两台机器仍然可以正常请求。
既然 ABC 都只负责部分功能,那为什么不在开发的时候就建立 3 个项目呢?这样岂不是更加清晰吗?的确可以这么做,但是我想说的是这样并不是必须的,或者说这不是重点,那么重点是什么?重点就是你如何确定这是 3 个项目而不是 4 个或者 5 个呢?是根据有 3 台机器我们就得有 3 个项目吗?所以重点就是如何找到进行拆分背后所隐含的那些逻辑,这些逻辑就是你的业务组织方式。
早前,我以为开发微服务就是把各种 Service 拆分出来当作一个独立的进程,使用独立的数据库,然后通过 RPC 进行相互调用,成功的把的注意力集中到了各种注册中心,网关,配置中心等等令人眼花缭乱的东西上面去了。在经历各种各样的填坑之后,回过头来再想一下,如果我只是作为一名开发,真的有必要去了解这些东西吗?我把大量的时间浪费在了去研究这些鬼东西上,反而把应该排在第一位的需求给丢到了一边。当服务网格和容器化出现以后,我对微服务这个词有了一些不一样的定义,说到底微服务终究不过是一种部署策略,它不是什么开发架构,它只是一系列指导如何正确开发服务的约定和理念,有了这些理念,我们就可以更容易的开发出适配部署运维的应用服务。微服务的终极目标,不是教我们如何用什么开发框架,用什么中间件,而是为了实现如何使资源利用得更加合理,更加有弹性,更加可伸缩。
        
     
    
    
    
        夏新 F9 ,6.2 元包邮,2000 毫安电仓,耳机电量连续使用 5 小时。
        
     
    
    
    
    
    
    
        每天撸一管算不算是一种运动呢,排泄一下应该还是挺有用处的,雄性激素过旺导致我头发溢脂性脱发了,发际线快要变成 M 形状了。
        
     
    
    
    
        我之前买了一个背包,结果用了一个月之后拉链坏掉了,觉得扔掉之后很可惜,然后我在网上买了十几米的拉链(几块钱包邮),自己一针一线的给换了,除了边角不好缝,其他的还好。花了 3 天时间缝完了,现在使用良好。
        
     
    
    
    
        事务是基于链接的,也就是说一旦你开启了一个事务,并且希望接下来的调用使用同一个事务,那么就必须使用同一个链接,就必须要把这个链接保存到一个地方,让所有使用数据库的方法都能够以一种相同的方式获取一个链接。
在 Java 中可以使用 ThreadLocal 来保存线程安全的变量,在当前线程的执行过程中,获取到同一个链接实例。如果是异步的,那就必须要考虑到链接的创建与提交,也就是要明确在什么时候开始,什么时候结束,Spring 的注解实现基于 AOP 的拦截,在“同步方法”调用之前开启事务,调用之后结束事务,它在背后实现了我上面第一段说的那些内容。
所以在没有 ThreadLocal 可以使用的时候,你必须要将一个链接进行传递,比如将链接封装到一个 Context 结构中,设计出一套接口标准,让所有使用数据库的代码都遵循这一套接口。不仅如此,还需要考虑到“同步”与“异步”的使用同一个链接将会带来怎样的影响,因为协程本质上也是在一个线程上运行,当多个协程同时运行在不同的线程时,就需要考虑到并发问题,因此不太建议“异步”使用一个事务。我对 Go 不太熟悉,但是背后的逻辑应该是以上这些内容。
        
     
    
    
    
        看情况
如果大多数情况令牌都足够充裕,第二种实际上是更好的做法,因为直接写了,相比第一种,少了一个读的操作。
如果大多数情况下令牌不够充裕,那么第二种相比第一种多了一个写的操作。
但是很显然,我们大概率无法提前得知哪种情况才是相对常见的,我个人的话会选择第一种。
        
     
    
    
    
        你有没有想过,有时候可能并不是单纯的技术原因所导致的,而是一次又一次变形的需求?层层加码,而又没有时间回过头来梳理和重构,必定会导致这些问题。
        
     
    
    
    
        吃褪黑素+1 ,不过第二天起床感觉有点怪怪的,就感觉大脑空白
        
     
    
    
    
        如果我们的眼光只局限在技术层面,那么 DDD 对你而言有用的就是战术模式那一部分,也就是编码的那一部分。如果我们把眼光放高一些,着手解决整个产品研发生命周期的效率方面,或者 DDD 就能帮大忙。这不仅仅使我们工作更加轻松,更加快乐,也使得我们不会把时间浪费在一些经常反复出现并且很愚蠢的事情上面。当然这个愿望很美好,但是不一定每个人都想做得这么美好。
        
     
    
    
    
        总的来说,DDD 分为两个部分,一个是技术实践的战术模式,一个是工程架构的战略模式。
其中,战术模式仅作为实现的部分参考,总结的是以面向对象范式编程语言的一些常用技巧与原则,提炼出了一些可以跟非技术人员沟通的构建单元,也就是你可以跟产品直接聊的一些东西,比如实体、值对象、仓库等等。
其实最重要的是战略模式,这部分也是大多数接触 DDD 的人觉得云雾缭绕的东西,看不见摸不着。团队规模小了,搞这些觉得繁琐,团队规模大了,面对已经成熟的 CRUD 基本上都有一套成熟的流程方案了。所以这个东西真正有价值的还是回归本质,解决软件核心中的复杂性。
首先你得是一个团队,否则的话一个人还搞什么 DDD 对吧?其次对团队里面的人也要有一定的要求,起码在沟通上,要明确价值。也就是说哪些信息对于不同岗位的人来说是明确的,是可以沟通的和达成共识的,哪些信息对开发或者产品来说就是废话,要把能够体现出真正用意的这部分提炼出来,在整个团队中进行传播和理解。
其次,有了高效的沟通和统一的理解以后,才能对同一个事物进行拓展(研发),需要在前者的基础之上,搭建一套能够迅速有效解决问题的工作流程,对产品进行高效的迭代。DDD 的战略部分就是基于前者,然后再结合一些准则和经验,帮助你如何解决更大规模的软件工程问题。
以上这些当然都是很美好的初衷,但是我个人认为,关键变量不在于每次迭代能否更进一步,而在于对人的管理,什么意思呢?人的不确定性才是最大的不确定性,人这个变量的影响范围如果能够控制住,培训也好,工作范围的划分也好,只要能够达到一种“柔性”的状态,终归会回归正轨。
说得有点多了,尽信书,不如无书,要有自己的思考。