From 48efa2dfde7c263f84ee5bb0872747034908d607 Mon Sep 17 00:00:00 2001 From: muqiuhan Date: Tue, 9 Sep 2025 06:04:57 +0000 Subject: deploy: 8bc5af8c3c1f0fc88407ba7d5df886ea71fdb12a --- .../index.html | 2 +- search.xml | 80 +++++++++++----------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/2025/09/09/database-fk-design-in-clinical-medicine/index.html b/2025/09/09/database-fk-design-in-clinical-medicine/index.html index 04de22de..78b23495 100644 --- a/2025/09/09/database-fk-design-in-clinical-medicine/index.html +++ b/2025/09/09/database-fk-design-in-clinical-medicine/index.html @@ -245,7 +245,7 @@

核心原则是:外键的存在与否取决于业务操作的后果严重性,而非单纯的技术指标。当数据断裂可能直接伤害患者时,必须用外键,当系统响应速度关乎生命时,则需设计更智能的补偿机制。

-

值得注意的是,现代云医疗数据库(如AWS HealthLake)已内置此类混合策略:在 OLTP 层保留关键外键,同时提供 FHIR 资源引用的逻辑一致性检查[^aws_healthlake]。开发者可以定期通过 Chaos Engineering 测试数据断裂场景,模拟删除患者记录后检查系统恢复能力。

+

不过现代云医疗数据库(如AWS HealthLake)已内置此类混合策略:在 OLTP 层保留关键外键,同时提供 FHIR 资源引用的逻辑一致性检查[^aws_healthlake]。开发者可以定期通过 Chaos Engineering 测试数据断裂场景,模拟删除患者记录后检查系统恢复能力。

参考文献:

[^theoretical_consistency]: Gray, J., & Reuter, A. (1993). Transaction Processing: Concepts and Techniques. Morgan Kaufmann.
[^tpc_c_performance]: CockroachDB 团队性能基准测试报告 (2020-2022)
[^cap_theorem]: Taft, R., et al. (2020). CockroachDB: The Resilient Geo-Distributed SQL Database. SIGMOD.
[^distributed_systems]: Google Cloud Architecture Center. (2022). Designing for Consistency in Distributed Databases.
[^fowler_architecture]: Fowler, M. (2003). Patterns of Enterprise Application Architecture. Addison-Wesley.
[^alibaba_architecture]: Alibaba Group. (2019). Nacos: A Dynamic Naming and Configuration Service for Cloud Native Applications.
[^data_integrity_issues]: Kleppmann, M. (2017). Designing Data-Intensive Applications. O’Reilly.
[^data_warehouse_challenges]: Netflix Technology Blog (2018). “When Data Relationships Break: Lessons from Recommendation Systems”
[^engineering_guidelines]: Kleppmann, M. (2020). Transaction Processing in Healthcare Systems. Communications of the ACM, 63(7).
[^aurora_logical_foreign_keys]: AWS Database Blog. (2021). Logical foreign keys in Amazon Aurora.
[^medical_data_criticality]: Jensen, P. B., et al. (2019). Mining Electronic Health Records: Towards Better Research Applications and Clinical Care. Nature Reviews Genetics.
[^fda_regulations]: U.S. Food and Drug Administration. (2023). 21 CFR Part 11: Electronic Records; Electronic Signatures.
[^pfa_data_quality]: Pfizer Clinical Data Science Team. (2022). Annual Data Quality Report. Internal Publication.
[^fhir_standard]: HL7 International. (2022). FHIR R4 Clinical Reasoning Module.
[^nhs_data_quality]: NHS Digital. (2022). Data Quality Framework for Healthcare Systems.
[^iso_medical_standard]: ISO/TR 20514:2021. Health informatics — Framework for integrity of health information.
[^data_governance_tools]: Johns Hopkins Medical Center Technical Report (2022). Data Governance in Chronic Disease Research.
[^mayo_clinic_case_study]: Mayo Clinic Proceedings. (2021). Design Patterns for Resilient Chronic Disease Management Systems. 96(8).
[^aws_healthlake]: AWS. (2023). HealthLake Security and Compliance Controls.

diff --git a/search.xml b/search.xml index 035ad1f4..99c95517 100644 --- a/search.xml +++ b/search.xml @@ -2577,7 +2577,7 @@ await prisma.$transaction(async tx => {

核心原则是:外键的存在与否取决于业务操作的后果严重性,而非单纯的技术指标。当数据断裂可能直接伤害患者时,必须用外键,当系统响应速度关乎生命时,则需设计更智能的补偿机制。

-

值得注意的是,现代云医疗数据库(如AWS HealthLake)已内置此类混合策略:在 OLTP 层保留关键外键,同时提供 FHIR 资源引用的逻辑一致性检查[^aws_healthlake]。开发者可以定期通过 Chaos Engineering 测试数据断裂场景,模拟删除患者记录后检查系统恢复能力。

+

不过现代云医疗数据库(如AWS HealthLake)已内置此类混合策略:在 OLTP 层保留关键外键,同时提供 FHIR 资源引用的逻辑一致性检查[^aws_healthlake]。开发者可以定期通过 Chaos Engineering 测试数据断裂场景,模拟删除患者记录后检查系统恢复能力。

参考文献:

[^theoretical_consistency]: Gray, J., & Reuter, A. (1993). Transaction Processing: Concepts and Techniques. Morgan Kaufmann.
[^tpc_c_performance]: CockroachDB 团队性能基准测试报告 (2020-2022)
[^cap_theorem]: Taft, R., et al. (2020). CockroachDB: The Resilient Geo-Distributed SQL Database. SIGMOD.
[^distributed_systems]: Google Cloud Architecture Center. (2022). Designing for Consistency in Distributed Databases.
[^fowler_architecture]: Fowler, M. (2003). Patterns of Enterprise Application Architecture. Addison-Wesley.
[^alibaba_architecture]: Alibaba Group. (2019). Nacos: A Dynamic Naming and Configuration Service for Cloud Native Applications.
[^data_integrity_issues]: Kleppmann, M. (2017). Designing Data-Intensive Applications. O’Reilly.
[^data_warehouse_challenges]: Netflix Technology Blog (2018). “When Data Relationships Break: Lessons from Recommendation Systems”
[^engineering_guidelines]: Kleppmann, M. (2020). Transaction Processing in Healthcare Systems. Communications of the ACM, 63(7).
[^aurora_logical_foreign_keys]: AWS Database Blog. (2021). Logical foreign keys in Amazon Aurora.
[^medical_data_criticality]: Jensen, P. B., et al. (2019). Mining Electronic Health Records: Towards Better Research Applications and Clinical Care. Nature Reviews Genetics.
[^fda_regulations]: U.S. Food and Drug Administration. (2023). 21 CFR Part 11: Electronic Records; Electronic Signatures.
[^pfa_data_quality]: Pfizer Clinical Data Science Team. (2022). Annual Data Quality Report. Internal Publication.
[^fhir_standard]: HL7 International. (2022). FHIR R4 Clinical Reasoning Module.
[^nhs_data_quality]: NHS Digital. (2022). Data Quality Framework for Healthcare Systems.
[^iso_medical_standard]: ISO/TR 20514:2021. Health informatics — Framework for integrity of health information.
[^data_governance_tools]: Johns Hopkins Medical Center Technical Report (2022). Data Governance in Chronic Disease Research.
[^mayo_clinic_case_study]: Mayo Clinic Proceedings. (2021). Design Patterns for Resilient Chronic Disease Management Systems. 96(8).
[^aws_healthlake]: AWS. (2023). HealthLake Security and Compliance Controls.

]]> @@ -5368,45 +5368,6 @@ await prisma.$transaction(async tx => { Life - - 隐藏一些OCaml Effect的机制,让其语法在精神上更接近delimcc - /2023/06/28/%E9%9A%90%E8%97%8F%E4%B8%80%E4%BA%9BOCaml-Effect%E7%9A%84%E6%9C%BA%E5%88%B6%EF%BC%8C%E8%AE%A9%E5%85%B6%E8%AF%AD%E6%B3%95%E5%9C%A8%E7%B2%BE%E7%A5%9E%E4%B8%8A%E6%9B%B4%E6%8E%A5%E8%BF%91delimcc/ - delimcc_of_fxhandler这个库在OCaml5的effect handlers上实现了一些delimcc原语(shift/reset, control/prompt这些):

-
let p = new_prompt () in
assert ([] = push_prompt p (fun () ->
1::2::take_subcont p (fun _k -> [])));
assert ([1;2] = push_prompt p (fun () ->
1::2::take_subcont p (fun k -> push_subcont k [])));
assert (135 =
let p1 = new_prompt () in
let p2 = new_prompt () in
let p3 = new_prompt () in
let pushtwice sk =
sk (fun () ->
sk (fun () ->
shift0 p2 (fun sk2 -> sk2 (fun () ->
sk2 (fun () -> 3))) ()))
in
push_prompt p1 (fun () ->
push_prompt p2 (fun () ->
push_prompt p3 (fun () -> shift0 p1 pushtwice ()) + 10) + 1) + 100);

print_endline "Success!"
- -

另外, avsm这里可以看到一些OCaml的Effect Syntax进展。

-

还有 multi-shot continuations in OCaml,在这个仓库里面还讨论了一些有趣的问题,例如,OCaml 编译器和runtime会做出一些假设从而进行一些优化,这些优化在使用multi-shot continutation时是不可取的(或完全错误的)。编译器优化导致错误的一个例子是堆到栈的转换,例如:

-
(* An illustration of how the heap to stack optimisation is broken.
* This example is adapted from de Vilhena and Pottier (2021).
* file: heap2stack.ml
* compile: ocamlopt -I $(opam var lib)/multicont multicont.cmxa heap2stack.ml
* run: ./a.out *)

(* We first require a little bit of setup. The following declares an
operation `Twice' which we use to implement multiple returns. *)
type _ Effect.t += Twice : unit Effect.t

(* The handler `htwice' interprets `Twice' by simply invoking its
continuation twice. *)
let htwice : (unit, unit) Effect.Deep.handler
= { retc = (fun x -> x)
; exnc = (fun e -> raise e)
; effc = (fun (type a) (eff : a Effect.t) ->
let open Effect.Deep in
match eff with
| Twice -> Some (fun (k : (a, _) continuation) ->
continue (Multicont.Deep.clone_continuation k) ();
continue k ())
| _ -> None) }

(* Now for the interesting stuff. In the code below, the compiler will
perform an escape analysis on the reference `i' and deduce that it
does not escape the local scope, because it is unaware of the
semantics of `perform Twice', hence the optimiser will transform
`i' into an immediate on the stack to save a heap allocation. As a
consequence, the assertion `(!i = 1)' will succeed twice, whereas
it should fail after the second return of `perform Twice'. *)
let heap2stack () =
Effect.Deep.match_with
(fun () ->
let i = ref 0 in
Effect.perform Twice;
i := !i + 1;
Printf.printf "i = %d\n%!" !i;
assert (!i = 1))
() htwice

(* The following does not trigger an assertion failure. *)
let _ = heap2stack ()

(* To fix this issue, we can wrap reference allocations in an instance
of `Sys.opaque_identity'. However, this is not really a viable fix
in general, as we may not have access to the client code that
allocates the reference! *)
let heap2stack' () =
Effect.Deep.match_with
(fun () ->
let i = Sys.opaque_identity (ref 0) in
Effect.perform Twice;
i := !i + 1;
Printf.printf "i = %d\n%!" !i;
assert (!i = 1))
() htwice

(* The following triggers an assertion failure. *)
let _ = heap2stack' ()
-]]>
- - Technique - -
- - 领域驱动设计中的“聚合根” - /2025/03/13/%E9%A2%86%E5%9F%9F%E9%A9%B1%E5%8A%A8%E8%AE%BE%E8%AE%A1%E4%B8%AD%E7%9A%84%E2%80%9C%E8%81%9A%E5%90%88%E6%A0%B9%E2%80%9D/ - 在领域驱动设计(Domain-Driven Design,简称DDD)中,聚合根(Aggregate Root)是聚合(Aggregate)中的核心实体,是一个聚合的入口点和控制者,负责维护聚合内部的一致性和不变性条件。聚合是一组紧密相关的领域对象的集合,这些对象通过一定的业务规则绑定在一起,并被视为一个单元。

-

主要的作用如下:

-
    -
  • 维护不变性:聚合根确保聚合内所有对象的一致性和不变性条件不被破坏。它负责封装与聚合相关的业务逻辑,保证聚合内的对象符合业务规则。
  • -
  • 管理生命周期:聚合根负责管理其内部对象的创建、修改和删除。它控制着聚合内部成员的生命周期,包括它们的创建、更新和删除。
  • -
  • 处理业务逻辑:聚合根负责处理与聚合相关的业务逻辑和操作,外部系统通过调用聚合根的方法来执行这些操作。它不仅是数据的容器,还负责封装与聚合相关的业务逻辑。
  • -
-

其具有以下特性:

-
    -
  • 唯一入口:聚合根是聚合内部对象的唯一入口,外部系统只能与聚合根交互,而无法直接访问聚合内部的其他对象。这样可以避免外部系统直接修改聚合内的实体,确保聚合的一致性和业务逻辑的完整性。
  • -
  • 标识唯一性:每个聚合根都有一个全局唯一的标识符(ID),用以区分不同的聚合实例。
  • -
  • 事务边界:聚合根常常作为事务的边界,确保事务内的所有操作要么全部成功,要么全部失败,以此来维护数据的完整性。
  • -
-

用 F# 来描述,以订单管理为例,大概写一下:

-
type OrderStatus = 
| New
| Shipped
| Delivered
| Cancelled

type OrderItem (productName: string, price: float, quantity: int) =
do
if quantity <= 0 then
failwith "Quantity must be positive"

member public this.ProductName = productName
member public this.Price = price
member public this.Quantity = quantity
member public this.TotalPrice () = price * quantity

type Order (id: int, customerName: string) =
let mutable status = OrderStatus.New
let mutable orderItems = []

member public this.Id = id
member public this.CustomerName = customerName
member public this.Status = status
member public this.OrderItems = orderItems

member public this.AddItem (item: OrderItem, price: float, quantity: int) =
if quantity <= 0 then
failwith "Quantity must be positive"

orderItems <- orderItems @ [OrderItem(item.ProductName, price, quantity)]

member public this.ChangeStatus (status: OrderStatus) =
this.Status <- status

member public this.TotalPrice () =
orderItems |> List.sumBy (fun item -> item.TotalPrice())

member public this.GetTotalPrice () =
orderItems |> List.sumBy (fun item -> item.TotalPrice())
- -

在这个例子中,Order 是聚合根,它通过 AddItem 方法来添加订单项,保证每个订单项符合业务规则。同时,聚合根 Order 还负责订单状态的管理,例如通过 ChangeStatus 方法来更新订单状态。OrderItem 是聚合内的一个实体,表示订单项,它通过 GetTotalPrice 方法来计算每个订单项的总价。外部系统只能通过 Order 聚合根来访问和操作订单项,而不能直接访问或修改 OrderItem

-]]>
- - Technique - -
金匮要略 /2023/03/04/%E9%87%91%E5%8C%AE%E8%A6%81%E7%95%A5/ @@ -6674,6 +6635,45 @@ await prisma.$transaction(async tx => { Medicine + + 隐藏一些OCaml Effect的机制,让其语法在精神上更接近delimcc + /2023/06/28/%E9%9A%90%E8%97%8F%E4%B8%80%E4%BA%9BOCaml-Effect%E7%9A%84%E6%9C%BA%E5%88%B6%EF%BC%8C%E8%AE%A9%E5%85%B6%E8%AF%AD%E6%B3%95%E5%9C%A8%E7%B2%BE%E7%A5%9E%E4%B8%8A%E6%9B%B4%E6%8E%A5%E8%BF%91delimcc/ + delimcc_of_fxhandler这个库在OCaml5的effect handlers上实现了一些delimcc原语(shift/reset, control/prompt这些):

+
let p = new_prompt () in
assert ([] = push_prompt p (fun () ->
1::2::take_subcont p (fun _k -> [])));
assert ([1;2] = push_prompt p (fun () ->
1::2::take_subcont p (fun k -> push_subcont k [])));
assert (135 =
let p1 = new_prompt () in
let p2 = new_prompt () in
let p3 = new_prompt () in
let pushtwice sk =
sk (fun () ->
sk (fun () ->
shift0 p2 (fun sk2 -> sk2 (fun () ->
sk2 (fun () -> 3))) ()))
in
push_prompt p1 (fun () ->
push_prompt p2 (fun () ->
push_prompt p3 (fun () -> shift0 p1 pushtwice ()) + 10) + 1) + 100);

print_endline "Success!"
+ +

另外, avsm这里可以看到一些OCaml的Effect Syntax进展。

+

还有 multi-shot continuations in OCaml,在这个仓库里面还讨论了一些有趣的问题,例如,OCaml 编译器和runtime会做出一些假设从而进行一些优化,这些优化在使用multi-shot continutation时是不可取的(或完全错误的)。编译器优化导致错误的一个例子是堆到栈的转换,例如:

+
(* An illustration of how the heap to stack optimisation is broken.
* This example is adapted from de Vilhena and Pottier (2021).
* file: heap2stack.ml
* compile: ocamlopt -I $(opam var lib)/multicont multicont.cmxa heap2stack.ml
* run: ./a.out *)

(* We first require a little bit of setup. The following declares an
operation `Twice' which we use to implement multiple returns. *)
type _ Effect.t += Twice : unit Effect.t

(* The handler `htwice' interprets `Twice' by simply invoking its
continuation twice. *)
let htwice : (unit, unit) Effect.Deep.handler
= { retc = (fun x -> x)
; exnc = (fun e -> raise e)
; effc = (fun (type a) (eff : a Effect.t) ->
let open Effect.Deep in
match eff with
| Twice -> Some (fun (k : (a, _) continuation) ->
continue (Multicont.Deep.clone_continuation k) ();
continue k ())
| _ -> None) }

(* Now for the interesting stuff. In the code below, the compiler will
perform an escape analysis on the reference `i' and deduce that it
does not escape the local scope, because it is unaware of the
semantics of `perform Twice', hence the optimiser will transform
`i' into an immediate on the stack to save a heap allocation. As a
consequence, the assertion `(!i = 1)' will succeed twice, whereas
it should fail after the second return of `perform Twice'. *)
let heap2stack () =
Effect.Deep.match_with
(fun () ->
let i = ref 0 in
Effect.perform Twice;
i := !i + 1;
Printf.printf "i = %d\n%!" !i;
assert (!i = 1))
() htwice

(* The following does not trigger an assertion failure. *)
let _ = heap2stack ()

(* To fix this issue, we can wrap reference allocations in an instance
of `Sys.opaque_identity'. However, this is not really a viable fix
in general, as we may not have access to the client code that
allocates the reference! *)
let heap2stack' () =
Effect.Deep.match_with
(fun () ->
let i = Sys.opaque_identity (ref 0) in
Effect.perform Twice;
i := !i + 1;
Printf.printf "i = %d\n%!" !i;
assert (!i = 1))
() htwice

(* The following triggers an assertion failure. *)
let _ = heap2stack' ()
+]]>
+ + Technique + +
+ + 领域驱动设计中的“聚合根” + /2025/03/13/%E9%A2%86%E5%9F%9F%E9%A9%B1%E5%8A%A8%E8%AE%BE%E8%AE%A1%E4%B8%AD%E7%9A%84%E2%80%9C%E8%81%9A%E5%90%88%E6%A0%B9%E2%80%9D/ + 在领域驱动设计(Domain-Driven Design,简称DDD)中,聚合根(Aggregate Root)是聚合(Aggregate)中的核心实体,是一个聚合的入口点和控制者,负责维护聚合内部的一致性和不变性条件。聚合是一组紧密相关的领域对象的集合,这些对象通过一定的业务规则绑定在一起,并被视为一个单元。

+

主要的作用如下:

+
    +
  • 维护不变性:聚合根确保聚合内所有对象的一致性和不变性条件不被破坏。它负责封装与聚合相关的业务逻辑,保证聚合内的对象符合业务规则。
  • +
  • 管理生命周期:聚合根负责管理其内部对象的创建、修改和删除。它控制着聚合内部成员的生命周期,包括它们的创建、更新和删除。
  • +
  • 处理业务逻辑:聚合根负责处理与聚合相关的业务逻辑和操作,外部系统通过调用聚合根的方法来执行这些操作。它不仅是数据的容器,还负责封装与聚合相关的业务逻辑。
  • +
+

其具有以下特性:

+
    +
  • 唯一入口:聚合根是聚合内部对象的唯一入口,外部系统只能与聚合根交互,而无法直接访问聚合内部的其他对象。这样可以避免外部系统直接修改聚合内的实体,确保聚合的一致性和业务逻辑的完整性。
  • +
  • 标识唯一性:每个聚合根都有一个全局唯一的标识符(ID),用以区分不同的聚合实例。
  • +
  • 事务边界:聚合根常常作为事务的边界,确保事务内的所有操作要么全部成功,要么全部失败,以此来维护数据的完整性。
  • +
+

用 F# 来描述,以订单管理为例,大概写一下:

+
type OrderStatus = 
| New
| Shipped
| Delivered
| Cancelled

type OrderItem (productName: string, price: float, quantity: int) =
do
if quantity <= 0 then
failwith "Quantity must be positive"

member public this.ProductName = productName
member public this.Price = price
member public this.Quantity = quantity
member public this.TotalPrice () = price * quantity

type Order (id: int, customerName: string) =
let mutable status = OrderStatus.New
let mutable orderItems = []

member public this.Id = id
member public this.CustomerName = customerName
member public this.Status = status
member public this.OrderItems = orderItems

member public this.AddItem (item: OrderItem, price: float, quantity: int) =
if quantity <= 0 then
failwith "Quantity must be positive"

orderItems <- orderItems @ [OrderItem(item.ProductName, price, quantity)]

member public this.ChangeStatus (status: OrderStatus) =
this.Status <- status

member public this.TotalPrice () =
orderItems |> List.sumBy (fun item -> item.TotalPrice())

member public this.GetTotalPrice () =
orderItems |> List.sumBy (fun item -> item.TotalPrice())
+ +

在这个例子中,Order 是聚合根,它通过 AddItem 方法来添加订单项,保证每个订单项符合业务规则。同时,聚合根 Order 还负责订单状态的管理,例如通过 ChangeStatus 方法来更新订单状态。OrderItem 是聚合内的一个实体,表示订单项,它通过 GetTotalPrice 方法来计算每个订单项的总价。外部系统只能通过 Order 聚合根来访问和操作订单项,而不能直接访问或修改 OrderItem

+]]>
+ + Technique + +
领域驱动设计中聚合根持久化和事件发布可能导致数据不一致问题 /2025/03/19/%E9%A2%86%E5%9F%9F%E9%A9%B1%E5%8A%A8%E8%AE%BE%E8%AE%A1%E4%B8%AD%E8%81%9A%E5%90%88%E6%A0%B9%E6%8C%81%E4%B9%85%E5%8C%96%E5%92%8C%E4%BA%8B%E4%BB%B6%E5%8F%91%E5%B8%83%E5%8F%AF%E8%83%BD%E5%AF%BC%E8%87%B4%E6%95%B0%E6%8D%AE%E4%B8%8D%E4%B8%80%E8%87%B4%E9%97%AE%E9%A2%98/ -- cgit v1.2.3