你有什么想法
if(!DoSomething()) return;
在 Clean Code 中,这被视为违反命令查询分离。但是我们如何理解命令 DoSomething() 中的某些内容是否出错?sql 命令(例如:void Delete(Table))呢?我们如何知道该表是否存在?
谢谢。
你有什么想法
if(!DoSomething()) return;
在 Clean Code 中,这被视为违反命令查询分离。但是我们如何理解命令 DoSomething() 中的某些内容是否出错?sql 命令(例如:void Delete(Table))呢?我们如何知道该表是否存在?
谢谢。
如果出现问题,DoSomething()
可能应该抛出异常,如果您作为调用者必须处理它。
例如:
try
{
DoSomething();
// .. do more after success
}
catch(SomeException ex) // maybe focus on a special error
{
// maybe do something special or just clean up!
}
我同意 rObiwahn 的评论,您应该CanDoSomething
在发出DoSomething
. 在纯 CQRS 环境中,DoSomething
不会返回任何东西,并且如果有任何东西阻止了某事的发生(不是由于异常,而是由于竞争条件或其他在 and 之间发生变化的东西CanDoSomething
)DoSomething
,您的域将发出一个DoSomethingWasInvalid
事件(或类似的东西),它将让您的应用程序最终变得一致。
这听起来可能很复杂,但是一旦您开始将逻辑分解为小块并允许您的应用程序实现最终一致性,它就会变得非常简单。
google 群里的 DDD/CQRS 群有很多不错的资源。诸如“您如何告诉发送者命令失败?' 有点类似于你的问题。像 Udi Dahan、Greg Young、Rinat Abdullin 和其他人这样的人监控着这个群体并提供了一些非常好的答案。我也建议不时检查一下。
希望这可以帮助!
我将在 Eiffel 中编写此示例以使其易于理解。
my_code
-- Calls the `do_something' routine
do
set_table ("my_table")
do_something
end
do_something
-- Something to do
require
valid_table: is_valid_table (table_name)
do
sql_list := execute_sql_on_table (table_name)
ensure
has_result: sql_list.count > 0
end
sql_list: ARRAYED_LIST [STUFF]
table_name: STRING
set_table (a_name: STRING)
-- Set `table_name' to `a_name'
require
has_name: not a_name.is_empty
valid_table: is_valid_table (a_name)
do
table_name := a_name
ensure
table_name_set: table_name.same_string (a_name)
end
delete_table (a_name: STRING)
-- Delete `a_name' from the database.
require
valid_table: is_valid_table (a_name)
do
execute_sql ("DROP TABLE " + a_name)
ensure
table_gone: not is_valid_table (a_name)
end
do_something' makes it the responsibility of the client
提供table_name' before making the call to
do_something'。do_something' fill the array
sql_list' 与 STUFF 实例的责任。table_name' is a query returning a reference pointer to a STRING, which is set with a "setter" command called
set_table'。在这种情况下,按合同设计的“合同”负责确保适当分离关注点以及谁负责上面这段代码中的内容。请注意代码中明显缺少 TRY-CATCH 结构。在这种情况下,数据源应该有“my_table”。合同的存在意味着当合同失败时软件将引发异常。要求失败表示调用者已损坏,而确保后置条件中的失败则指向供应商功能。
最后,该代码展示了明确的命令-查询-分离以及从契约式设计中获得的质量保证的应用。因此,可以回答原始问题:
“但是我们如何理解命令 DoSomething() 中的某些内容是否出错?那么 sql 命令(例如:void Delete(Table))呢?我们如何知道该表是否存在?”
虽然对 delete_table ("my_table") 的调用可能会被注入某个祖先或可能发生在另一个线程上,但这是do_something'. As long as those contracts stand guard over calls to
do_something 中的合同的用途,但该过程将得到适当的处理。对“delete_table”的注入调用只会导致合约失败。
所有这一切都假设在“my_table”上 DROP TABLE 是不可行的,并且这样做是不幸的意外。但是,如果可以在“my_table”上删除 TABLE,则需要重试机制或其他“处理程序”来管理此用例,并且上面的代码将不起作用。
我现在真的想到了这件事,[为什么我们不考虑“关注点分离”而不是“关注点分离”!]我知道它离题,但过多地推动标准将导致无处可去。从人类历史上很容易看出有多少实践/标准被时间证明是错误的!这完全取决于您对卓越的看法。
所以在这种情况下,我总是试着去想相反的事情来保持真实。我想说更多,但从我回答的角度来看,我认为这已经足够了;)
祝你好运!