From/Into
While building software, especially with layered architectures, implementing conversions in the higher layers, like REST inputs into Commands, or Postgres query Results into Entities, is fundamental. If multiple objects need conversion into one, an aggregate object implementing the To pattern should be created first.
Leveraging the From/To pattern is akin to preferring Dependency Injection over explicit import, promoting decoupling and enhancing code maintainability, testability, and readability. It allows the software to be more adaptable to change, and its components more interchangeable, giving developers the ability to switch implementations with minimal hassle.
It's always the outer layer's responsibility to convert the data into the format it needs. The inner layers should not be aware of the outer layers.
How to Implement
// Retrieved from outside
struct ApiResponse {
first_name: String,
last_name: String,
}
// Used internally
struct Fullname(String);
// Returned to outside
struct ClientResponse {
fullname: String,
}
impl Into<Fullname> for ApiResponse {
fn into(self) -> Fullname {
Fullname(format!("{} {}", self.first_name, self.last_name))
}
}
impl From<Fullname> for ClientResponse {
fn from(fullname: Fullname) -> Self {
ClientResponse {
fullname: fullname.0,
}
}
}