Am I breaking OOP practice with this architecture?
I have a web application. I don't believe the technology is important. The structure is an N-tier application, shown in the image on the left. There are 3 layers.
UI (MVC pattern), Business Logic Layer (BLL) and Data Access Layer (DAL)
The problem I have is my BLL is massive as it has the logic and paths through the application events call.
A typical flow through the application could be:
Event fired in UI, traverse to a method in the BLL, perform logic (possibly in multiple parts of the BLL), eventually to the DAL, back to the BLL (where likely more logic) and then return some value to the UI.
The BLL in this example is very busy and I'm thinking how to split this out. I also have the logic and the objects combined which I don't like.
The version on the right is my effort.
The Logic is still how the application flows between UI and DAL, but there are likely no properties... Only methods (the majority of classes in this layer could possibly be static as they don't store any state). The Poco layer is where classes exist which do have properties (such as a Person class where there would be name, age, height etc). These would have nothing to do with the flow of the application, they only store state.
The flow could be:
Even triggered from UI and passes some data to the UI layer controller (MVC). This translates the raw data and converts it into the poco model. The poco model is then passed into the Logic layer (which was the BLL) and eventually to the command query layer, potentially manipulated on the way. The Command query layer converts the POCO to a database object (which are nearly the same thing, but one is designed for persistence, the other for the front end). The item is stored and a database object is returned to the Command Query layer. It is then converted into a POCO, where it returns to the Logic layer, potentially processed further and then finally, back to the UI
The Shared logic and interfaces is where we may have persistent data, such as MaxNumberOf_X and TotalAllowed_X and all the interfaces.
Both the shared logic/interfaces and DAL are the "base" of the architecture. These know nothing about the outside world.
Everything knows about poco other than the shared logic/interfaces and DAL.
The flow is still very similar to the first example, but it's made each layer more responsible for 1 thing (be it state, flow or anything else)... but am I breaking OOP with this approach?
An example to demo the Logic and Poco could be:
public class LogicClass
{
private ICommandQueryObject cmdQuery;
public PocoA Method1(PocoB pocoB)
{
return cmdQuery.Save(pocoB);
}
/*This has no state objects, only ways to communicate with other
layers such as the cmdQuery. Everything else is just function
calls to allow flow via the program */
public PocoA Method2(PocoB pocoB)
{
pocoB.UpdateState("world");
return Method1(pocoB);
}
}
public struct PocoX
{
public string DataA {get;set;}
public int DataB {get;set;}
public int DataC {get;set;}
/*This simply returns something that is part of this class.
Everything is self-contained to this class. It doesn't call
trying to directly communicate with databases etc*/
public int GetValue()
{
return DataB * DataC;
}
/*This simply sets something that is part of this class.
Everything is self-contained to this class.
It doesn't call trying to directly communicate with databases etc*/
public void UpdateState(string input)
{
DataA += input;
}
}
object-oriented architecture
add a comment |
I have a web application. I don't believe the technology is important. The structure is an N-tier application, shown in the image on the left. There are 3 layers.
UI (MVC pattern), Business Logic Layer (BLL) and Data Access Layer (DAL)
The problem I have is my BLL is massive as it has the logic and paths through the application events call.
A typical flow through the application could be:
Event fired in UI, traverse to a method in the BLL, perform logic (possibly in multiple parts of the BLL), eventually to the DAL, back to the BLL (where likely more logic) and then return some value to the UI.
The BLL in this example is very busy and I'm thinking how to split this out. I also have the logic and the objects combined which I don't like.
The version on the right is my effort.
The Logic is still how the application flows between UI and DAL, but there are likely no properties... Only methods (the majority of classes in this layer could possibly be static as they don't store any state). The Poco layer is where classes exist which do have properties (such as a Person class where there would be name, age, height etc). These would have nothing to do with the flow of the application, they only store state.
The flow could be:
Even triggered from UI and passes some data to the UI layer controller (MVC). This translates the raw data and converts it into the poco model. The poco model is then passed into the Logic layer (which was the BLL) and eventually to the command query layer, potentially manipulated on the way. The Command query layer converts the POCO to a database object (which are nearly the same thing, but one is designed for persistence, the other for the front end). The item is stored and a database object is returned to the Command Query layer. It is then converted into a POCO, where it returns to the Logic layer, potentially processed further and then finally, back to the UI
The Shared logic and interfaces is where we may have persistent data, such as MaxNumberOf_X and TotalAllowed_X and all the interfaces.
Both the shared logic/interfaces and DAL are the "base" of the architecture. These know nothing about the outside world.
Everything knows about poco other than the shared logic/interfaces and DAL.
The flow is still very similar to the first example, but it's made each layer more responsible for 1 thing (be it state, flow or anything else)... but am I breaking OOP with this approach?
An example to demo the Logic and Poco could be:
public class LogicClass
{
private ICommandQueryObject cmdQuery;
public PocoA Method1(PocoB pocoB)
{
return cmdQuery.Save(pocoB);
}
/*This has no state objects, only ways to communicate with other
layers such as the cmdQuery. Everything else is just function
calls to allow flow via the program */
public PocoA Method2(PocoB pocoB)
{
pocoB.UpdateState("world");
return Method1(pocoB);
}
}
public struct PocoX
{
public string DataA {get;set;}
public int DataB {get;set;}
public int DataC {get;set;}
/*This simply returns something that is part of this class.
Everything is self-contained to this class. It doesn't call
trying to directly communicate with databases etc*/
public int GetValue()
{
return DataB * DataC;
}
/*This simply sets something that is part of this class.
Everything is self-contained to this class.
It doesn't call trying to directly communicate with databases etc*/
public void UpdateState(string input)
{
DataA += input;
}
}
object-oriented architecture
I don't see anything fundamentally wrong with your architecture as you've currently described it.
– Robert Harvey♦
3 hours ago
3
There isn't enough functional detail in your code example to provide any further insight. Foobar examples seldom provide sufficient illustration.
– Robert Harvey♦
3 hours ago
add a comment |
I have a web application. I don't believe the technology is important. The structure is an N-tier application, shown in the image on the left. There are 3 layers.
UI (MVC pattern), Business Logic Layer (BLL) and Data Access Layer (DAL)
The problem I have is my BLL is massive as it has the logic and paths through the application events call.
A typical flow through the application could be:
Event fired in UI, traverse to a method in the BLL, perform logic (possibly in multiple parts of the BLL), eventually to the DAL, back to the BLL (where likely more logic) and then return some value to the UI.
The BLL in this example is very busy and I'm thinking how to split this out. I also have the logic and the objects combined which I don't like.
The version on the right is my effort.
The Logic is still how the application flows between UI and DAL, but there are likely no properties... Only methods (the majority of classes in this layer could possibly be static as they don't store any state). The Poco layer is where classes exist which do have properties (such as a Person class where there would be name, age, height etc). These would have nothing to do with the flow of the application, they only store state.
The flow could be:
Even triggered from UI and passes some data to the UI layer controller (MVC). This translates the raw data and converts it into the poco model. The poco model is then passed into the Logic layer (which was the BLL) and eventually to the command query layer, potentially manipulated on the way. The Command query layer converts the POCO to a database object (which are nearly the same thing, but one is designed for persistence, the other for the front end). The item is stored and a database object is returned to the Command Query layer. It is then converted into a POCO, where it returns to the Logic layer, potentially processed further and then finally, back to the UI
The Shared logic and interfaces is where we may have persistent data, such as MaxNumberOf_X and TotalAllowed_X and all the interfaces.
Both the shared logic/interfaces and DAL are the "base" of the architecture. These know nothing about the outside world.
Everything knows about poco other than the shared logic/interfaces and DAL.
The flow is still very similar to the first example, but it's made each layer more responsible for 1 thing (be it state, flow or anything else)... but am I breaking OOP with this approach?
An example to demo the Logic and Poco could be:
public class LogicClass
{
private ICommandQueryObject cmdQuery;
public PocoA Method1(PocoB pocoB)
{
return cmdQuery.Save(pocoB);
}
/*This has no state objects, only ways to communicate with other
layers such as the cmdQuery. Everything else is just function
calls to allow flow via the program */
public PocoA Method2(PocoB pocoB)
{
pocoB.UpdateState("world");
return Method1(pocoB);
}
}
public struct PocoX
{
public string DataA {get;set;}
public int DataB {get;set;}
public int DataC {get;set;}
/*This simply returns something that is part of this class.
Everything is self-contained to this class. It doesn't call
trying to directly communicate with databases etc*/
public int GetValue()
{
return DataB * DataC;
}
/*This simply sets something that is part of this class.
Everything is self-contained to this class.
It doesn't call trying to directly communicate with databases etc*/
public void UpdateState(string input)
{
DataA += input;
}
}
object-oriented architecture
I have a web application. I don't believe the technology is important. The structure is an N-tier application, shown in the image on the left. There are 3 layers.
UI (MVC pattern), Business Logic Layer (BLL) and Data Access Layer (DAL)
The problem I have is my BLL is massive as it has the logic and paths through the application events call.
A typical flow through the application could be:
Event fired in UI, traverse to a method in the BLL, perform logic (possibly in multiple parts of the BLL), eventually to the DAL, back to the BLL (where likely more logic) and then return some value to the UI.
The BLL in this example is very busy and I'm thinking how to split this out. I also have the logic and the objects combined which I don't like.
The version on the right is my effort.
The Logic is still how the application flows between UI and DAL, but there are likely no properties... Only methods (the majority of classes in this layer could possibly be static as they don't store any state). The Poco layer is where classes exist which do have properties (such as a Person class where there would be name, age, height etc). These would have nothing to do with the flow of the application, they only store state.
The flow could be:
Even triggered from UI and passes some data to the UI layer controller (MVC). This translates the raw data and converts it into the poco model. The poco model is then passed into the Logic layer (which was the BLL) and eventually to the command query layer, potentially manipulated on the way. The Command query layer converts the POCO to a database object (which are nearly the same thing, but one is designed for persistence, the other for the front end). The item is stored and a database object is returned to the Command Query layer. It is then converted into a POCO, where it returns to the Logic layer, potentially processed further and then finally, back to the UI
The Shared logic and interfaces is where we may have persistent data, such as MaxNumberOf_X and TotalAllowed_X and all the interfaces.
Both the shared logic/interfaces and DAL are the "base" of the architecture. These know nothing about the outside world.
Everything knows about poco other than the shared logic/interfaces and DAL.
The flow is still very similar to the first example, but it's made each layer more responsible for 1 thing (be it state, flow or anything else)... but am I breaking OOP with this approach?
An example to demo the Logic and Poco could be:
public class LogicClass
{
private ICommandQueryObject cmdQuery;
public PocoA Method1(PocoB pocoB)
{
return cmdQuery.Save(pocoB);
}
/*This has no state objects, only ways to communicate with other
layers such as the cmdQuery. Everything else is just function
calls to allow flow via the program */
public PocoA Method2(PocoB pocoB)
{
pocoB.UpdateState("world");
return Method1(pocoB);
}
}
public struct PocoX
{
public string DataA {get;set;}
public int DataB {get;set;}
public int DataC {get;set;}
/*This simply returns something that is part of this class.
Everything is self-contained to this class. It doesn't call
trying to directly communicate with databases etc*/
public int GetValue()
{
return DataB * DataC;
}
/*This simply sets something that is part of this class.
Everything is self-contained to this class.
It doesn't call trying to directly communicate with databases etc*/
public void UpdateState(string input)
{
DataA += input;
}
}
object-oriented architecture
object-oriented architecture
edited 3 hours ago
Laiv
6,95811241
6,95811241
asked 4 hours ago
MyDaftQuestionsMyDaftQuestions
7982810
7982810
I don't see anything fundamentally wrong with your architecture as you've currently described it.
– Robert Harvey♦
3 hours ago
3
There isn't enough functional detail in your code example to provide any further insight. Foobar examples seldom provide sufficient illustration.
– Robert Harvey♦
3 hours ago
add a comment |
I don't see anything fundamentally wrong with your architecture as you've currently described it.
– Robert Harvey♦
3 hours ago
3
There isn't enough functional detail in your code example to provide any further insight. Foobar examples seldom provide sufficient illustration.
– Robert Harvey♦
3 hours ago
I don't see anything fundamentally wrong with your architecture as you've currently described it.
– Robert Harvey♦
3 hours ago
I don't see anything fundamentally wrong with your architecture as you've currently described it.
– Robert Harvey♦
3 hours ago
3
3
There isn't enough functional detail in your code example to provide any further insight. Foobar examples seldom provide sufficient illustration.
– Robert Harvey♦
3 hours ago
There isn't enough functional detail in your code example to provide any further insight. Foobar examples seldom provide sufficient illustration.
– Robert Harvey♦
3 hours ago
add a comment |
3 Answers
3
active
oldest
votes
Yes, you are very likely breaking core OOP concepts. However don't feel bad, people do this all the time, it doesn't mean that your architecture is "wrong". I would say it is probably less maintainable than a proper OO design, but this is rather subjective and not your question anyway. (Here is an article of mine criticizing the n-tier architecture in general).
Reasoning: The most basic concept of OOP is that data and logic form a single unit (an object). Although this is a very simplistic and mechanical statement, even so, it is not really followed in your design (if I understand you correctly). You are quite clearly separating most of the data from most of the logic. Having stateless (static-like) methods for example is called "procedures", and are generally antithetic to OOP.
There are of course always exceptions, but this design violates these things as a rule.
Again, I would like to stress "violates OOP" != "wrong", so this is not necessarily a value judgement. It all depends on your architecture constraints, maintainability use-cases, requirements, etc.
1
Have an upvote, this is a good answer, if I were writing my own, I would copy & paste this, but also add that, if you find your self not writing OOP code, perhaps you should consider a non-OOP language as it comes with a lot of extra overhead that you can do without if you aren't using it
– TheCatWhisperer
1 hour ago
add a comment |
One of the core principles of Functional Programming is pure functions.
One of the core principles of Object Oriented Programming is putting functions together with the data they act on.
Both of these core principles fall away when your application has to communicate with the outside world. Indeed you can only be true to these ideals in a specially prepared space in your system. Not every line of your code must meet these ideals. But if no line of your code meets these ideals you can't really claim to be using OOP or FP.
So it's OK to have data only "objects" that you fling around because you need them to cross a boundary that you simply can't refactor to move the interested code across. Just know that isn't OOP. That's reality. OOP is when, once inside that boundary you gather all the logic that acts on that data into one place.
Not that you have to do that either. OOP isn't all things to all people. It is what it is. Just don't claim something follows OOP when it doesn't or you're going to confuse people trying to maintain your code.
Your POCO's seem to have business logic in them just fine so I wouldn't worry about to much about being anemic. What does concern me is they all seem very mutable. Remember that getters and setters don't provide real encapsulation. If your POCO is headed for that boundry then fine. Just understand this isn't giving you the full benefits of a real encapsulated OOP object. Some call this a Data Transfer Object or DTO.
A trick I've used successfully is to craft OOP objects that eat DTO's. I use the DTO as a parameter object. My constructor reads state from it (read as defensive copy) and tosses it aside. Now I've got a fully encapsulated and immutable version of the DTO. I can move all methods concerned with this data can be moved here provided they're on this side of that boundary.
I don't provide getters or setters. I follow tell, don't ask. You call my methods and they go do what needs doing. They likely don't even tell you what they did. They just do it.
Now eventually something, somewhere is going to run into another boundary and this all falls apart again. That's fine. Spin up another DTO and toss it over the wall.
This is the essence of what the ports and adapters architecture is all about. I've been reading about it from a functional perspective. Maybe it'll interest you too.
add a comment |
If I read your explanation correctly your objects look a bit like this: (tricky without context)
public class LogicClass
{
private ICommandQueryObject cmdQuery;
public PocoA Method(PocoB pocoB) { ... }
}
public class PocoX
{
public string DataA {get;set;}
public int DataB {get;set;}
... etc
}
In that your Poco classes contain only data and your Logic classes contain the methods which act on that data; yes, you have broken the principles of "Classic OOP"
Again, it's hard to tell from your generalised description, but I would hazard that what you have written could be categorized as Anemic Domain Model.
I don't think this is a particularly bad approach, nor, if you consider your Poco's as structs does it nescarly break OOP in the more specific sense. In that your Objects are now the LogicClasses. Indeed if you make your Pocos immutable the design could be considered quite Functional.
However, when you reference Shared Logic, Pocos that are almost but not the same and statics I start to worry about the detail of your design.
I've added to my post, essentially copying your example. Sorry ti wasn't clear to start with
– MyDaftQuestions
3 hours ago
1
what I mean is, if you told us what the application does it would be easier to write examples. Instead of LogicClass you could have PaymentProvider or whatever
– Ewan
2 hours ago
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "131"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsoftwareengineering.stackexchange.com%2fquestions%2f389638%2fam-i-breaking-oop-practice-with-this-architecture%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
Yes, you are very likely breaking core OOP concepts. However don't feel bad, people do this all the time, it doesn't mean that your architecture is "wrong". I would say it is probably less maintainable than a proper OO design, but this is rather subjective and not your question anyway. (Here is an article of mine criticizing the n-tier architecture in general).
Reasoning: The most basic concept of OOP is that data and logic form a single unit (an object). Although this is a very simplistic and mechanical statement, even so, it is not really followed in your design (if I understand you correctly). You are quite clearly separating most of the data from most of the logic. Having stateless (static-like) methods for example is called "procedures", and are generally antithetic to OOP.
There are of course always exceptions, but this design violates these things as a rule.
Again, I would like to stress "violates OOP" != "wrong", so this is not necessarily a value judgement. It all depends on your architecture constraints, maintainability use-cases, requirements, etc.
1
Have an upvote, this is a good answer, if I were writing my own, I would copy & paste this, but also add that, if you find your self not writing OOP code, perhaps you should consider a non-OOP language as it comes with a lot of extra overhead that you can do without if you aren't using it
– TheCatWhisperer
1 hour ago
add a comment |
Yes, you are very likely breaking core OOP concepts. However don't feel bad, people do this all the time, it doesn't mean that your architecture is "wrong". I would say it is probably less maintainable than a proper OO design, but this is rather subjective and not your question anyway. (Here is an article of mine criticizing the n-tier architecture in general).
Reasoning: The most basic concept of OOP is that data and logic form a single unit (an object). Although this is a very simplistic and mechanical statement, even so, it is not really followed in your design (if I understand you correctly). You are quite clearly separating most of the data from most of the logic. Having stateless (static-like) methods for example is called "procedures", and are generally antithetic to OOP.
There are of course always exceptions, but this design violates these things as a rule.
Again, I would like to stress "violates OOP" != "wrong", so this is not necessarily a value judgement. It all depends on your architecture constraints, maintainability use-cases, requirements, etc.
1
Have an upvote, this is a good answer, if I were writing my own, I would copy & paste this, but also add that, if you find your self not writing OOP code, perhaps you should consider a non-OOP language as it comes with a lot of extra overhead that you can do without if you aren't using it
– TheCatWhisperer
1 hour ago
add a comment |
Yes, you are very likely breaking core OOP concepts. However don't feel bad, people do this all the time, it doesn't mean that your architecture is "wrong". I would say it is probably less maintainable than a proper OO design, but this is rather subjective and not your question anyway. (Here is an article of mine criticizing the n-tier architecture in general).
Reasoning: The most basic concept of OOP is that data and logic form a single unit (an object). Although this is a very simplistic and mechanical statement, even so, it is not really followed in your design (if I understand you correctly). You are quite clearly separating most of the data from most of the logic. Having stateless (static-like) methods for example is called "procedures", and are generally antithetic to OOP.
There are of course always exceptions, but this design violates these things as a rule.
Again, I would like to stress "violates OOP" != "wrong", so this is not necessarily a value judgement. It all depends on your architecture constraints, maintainability use-cases, requirements, etc.
Yes, you are very likely breaking core OOP concepts. However don't feel bad, people do this all the time, it doesn't mean that your architecture is "wrong". I would say it is probably less maintainable than a proper OO design, but this is rather subjective and not your question anyway. (Here is an article of mine criticizing the n-tier architecture in general).
Reasoning: The most basic concept of OOP is that data and logic form a single unit (an object). Although this is a very simplistic and mechanical statement, even so, it is not really followed in your design (if I understand you correctly). You are quite clearly separating most of the data from most of the logic. Having stateless (static-like) methods for example is called "procedures", and are generally antithetic to OOP.
There are of course always exceptions, but this design violates these things as a rule.
Again, I would like to stress "violates OOP" != "wrong", so this is not necessarily a value judgement. It all depends on your architecture constraints, maintainability use-cases, requirements, etc.
answered 3 hours ago
Robert BräutigamRobert Bräutigam
1,934611
1,934611
1
Have an upvote, this is a good answer, if I were writing my own, I would copy & paste this, but also add that, if you find your self not writing OOP code, perhaps you should consider a non-OOP language as it comes with a lot of extra overhead that you can do without if you aren't using it
– TheCatWhisperer
1 hour ago
add a comment |
1
Have an upvote, this is a good answer, if I were writing my own, I would copy & paste this, but also add that, if you find your self not writing OOP code, perhaps you should consider a non-OOP language as it comes with a lot of extra overhead that you can do without if you aren't using it
– TheCatWhisperer
1 hour ago
1
1
Have an upvote, this is a good answer, if I were writing my own, I would copy & paste this, but also add that, if you find your self not writing OOP code, perhaps you should consider a non-OOP language as it comes with a lot of extra overhead that you can do without if you aren't using it
– TheCatWhisperer
1 hour ago
Have an upvote, this is a good answer, if I were writing my own, I would copy & paste this, but also add that, if you find your self not writing OOP code, perhaps you should consider a non-OOP language as it comes with a lot of extra overhead that you can do without if you aren't using it
– TheCatWhisperer
1 hour ago
add a comment |
One of the core principles of Functional Programming is pure functions.
One of the core principles of Object Oriented Programming is putting functions together with the data they act on.
Both of these core principles fall away when your application has to communicate with the outside world. Indeed you can only be true to these ideals in a specially prepared space in your system. Not every line of your code must meet these ideals. But if no line of your code meets these ideals you can't really claim to be using OOP or FP.
So it's OK to have data only "objects" that you fling around because you need them to cross a boundary that you simply can't refactor to move the interested code across. Just know that isn't OOP. That's reality. OOP is when, once inside that boundary you gather all the logic that acts on that data into one place.
Not that you have to do that either. OOP isn't all things to all people. It is what it is. Just don't claim something follows OOP when it doesn't or you're going to confuse people trying to maintain your code.
Your POCO's seem to have business logic in them just fine so I wouldn't worry about to much about being anemic. What does concern me is they all seem very mutable. Remember that getters and setters don't provide real encapsulation. If your POCO is headed for that boundry then fine. Just understand this isn't giving you the full benefits of a real encapsulated OOP object. Some call this a Data Transfer Object or DTO.
A trick I've used successfully is to craft OOP objects that eat DTO's. I use the DTO as a parameter object. My constructor reads state from it (read as defensive copy) and tosses it aside. Now I've got a fully encapsulated and immutable version of the DTO. I can move all methods concerned with this data can be moved here provided they're on this side of that boundary.
I don't provide getters or setters. I follow tell, don't ask. You call my methods and they go do what needs doing. They likely don't even tell you what they did. They just do it.
Now eventually something, somewhere is going to run into another boundary and this all falls apart again. That's fine. Spin up another DTO and toss it over the wall.
This is the essence of what the ports and adapters architecture is all about. I've been reading about it from a functional perspective. Maybe it'll interest you too.
add a comment |
One of the core principles of Functional Programming is pure functions.
One of the core principles of Object Oriented Programming is putting functions together with the data they act on.
Both of these core principles fall away when your application has to communicate with the outside world. Indeed you can only be true to these ideals in a specially prepared space in your system. Not every line of your code must meet these ideals. But if no line of your code meets these ideals you can't really claim to be using OOP or FP.
So it's OK to have data only "objects" that you fling around because you need them to cross a boundary that you simply can't refactor to move the interested code across. Just know that isn't OOP. That's reality. OOP is when, once inside that boundary you gather all the logic that acts on that data into one place.
Not that you have to do that either. OOP isn't all things to all people. It is what it is. Just don't claim something follows OOP when it doesn't or you're going to confuse people trying to maintain your code.
Your POCO's seem to have business logic in them just fine so I wouldn't worry about to much about being anemic. What does concern me is they all seem very mutable. Remember that getters and setters don't provide real encapsulation. If your POCO is headed for that boundry then fine. Just understand this isn't giving you the full benefits of a real encapsulated OOP object. Some call this a Data Transfer Object or DTO.
A trick I've used successfully is to craft OOP objects that eat DTO's. I use the DTO as a parameter object. My constructor reads state from it (read as defensive copy) and tosses it aside. Now I've got a fully encapsulated and immutable version of the DTO. I can move all methods concerned with this data can be moved here provided they're on this side of that boundary.
I don't provide getters or setters. I follow tell, don't ask. You call my methods and they go do what needs doing. They likely don't even tell you what they did. They just do it.
Now eventually something, somewhere is going to run into another boundary and this all falls apart again. That's fine. Spin up another DTO and toss it over the wall.
This is the essence of what the ports and adapters architecture is all about. I've been reading about it from a functional perspective. Maybe it'll interest you too.
add a comment |
One of the core principles of Functional Programming is pure functions.
One of the core principles of Object Oriented Programming is putting functions together with the data they act on.
Both of these core principles fall away when your application has to communicate with the outside world. Indeed you can only be true to these ideals in a specially prepared space in your system. Not every line of your code must meet these ideals. But if no line of your code meets these ideals you can't really claim to be using OOP or FP.
So it's OK to have data only "objects" that you fling around because you need them to cross a boundary that you simply can't refactor to move the interested code across. Just know that isn't OOP. That's reality. OOP is when, once inside that boundary you gather all the logic that acts on that data into one place.
Not that you have to do that either. OOP isn't all things to all people. It is what it is. Just don't claim something follows OOP when it doesn't or you're going to confuse people trying to maintain your code.
Your POCO's seem to have business logic in them just fine so I wouldn't worry about to much about being anemic. What does concern me is they all seem very mutable. Remember that getters and setters don't provide real encapsulation. If your POCO is headed for that boundry then fine. Just understand this isn't giving you the full benefits of a real encapsulated OOP object. Some call this a Data Transfer Object or DTO.
A trick I've used successfully is to craft OOP objects that eat DTO's. I use the DTO as a parameter object. My constructor reads state from it (read as defensive copy) and tosses it aside. Now I've got a fully encapsulated and immutable version of the DTO. I can move all methods concerned with this data can be moved here provided they're on this side of that boundary.
I don't provide getters or setters. I follow tell, don't ask. You call my methods and they go do what needs doing. They likely don't even tell you what they did. They just do it.
Now eventually something, somewhere is going to run into another boundary and this all falls apart again. That's fine. Spin up another DTO and toss it over the wall.
This is the essence of what the ports and adapters architecture is all about. I've been reading about it from a functional perspective. Maybe it'll interest you too.
One of the core principles of Functional Programming is pure functions.
One of the core principles of Object Oriented Programming is putting functions together with the data they act on.
Both of these core principles fall away when your application has to communicate with the outside world. Indeed you can only be true to these ideals in a specially prepared space in your system. Not every line of your code must meet these ideals. But if no line of your code meets these ideals you can't really claim to be using OOP or FP.
So it's OK to have data only "objects" that you fling around because you need them to cross a boundary that you simply can't refactor to move the interested code across. Just know that isn't OOP. That's reality. OOP is when, once inside that boundary you gather all the logic that acts on that data into one place.
Not that you have to do that either. OOP isn't all things to all people. It is what it is. Just don't claim something follows OOP when it doesn't or you're going to confuse people trying to maintain your code.
Your POCO's seem to have business logic in them just fine so I wouldn't worry about to much about being anemic. What does concern me is they all seem very mutable. Remember that getters and setters don't provide real encapsulation. If your POCO is headed for that boundry then fine. Just understand this isn't giving you the full benefits of a real encapsulated OOP object. Some call this a Data Transfer Object or DTO.
A trick I've used successfully is to craft OOP objects that eat DTO's. I use the DTO as a parameter object. My constructor reads state from it (read as defensive copy) and tosses it aside. Now I've got a fully encapsulated and immutable version of the DTO. I can move all methods concerned with this data can be moved here provided they're on this side of that boundary.
I don't provide getters or setters. I follow tell, don't ask. You call my methods and they go do what needs doing. They likely don't even tell you what they did. They just do it.
Now eventually something, somewhere is going to run into another boundary and this all falls apart again. That's fine. Spin up another DTO and toss it over the wall.
This is the essence of what the ports and adapters architecture is all about. I've been reading about it from a functional perspective. Maybe it'll interest you too.
edited 1 hour ago
answered 1 hour ago
candied_orangecandied_orange
54.9k17104191
54.9k17104191
add a comment |
add a comment |
If I read your explanation correctly your objects look a bit like this: (tricky without context)
public class LogicClass
{
private ICommandQueryObject cmdQuery;
public PocoA Method(PocoB pocoB) { ... }
}
public class PocoX
{
public string DataA {get;set;}
public int DataB {get;set;}
... etc
}
In that your Poco classes contain only data and your Logic classes contain the methods which act on that data; yes, you have broken the principles of "Classic OOP"
Again, it's hard to tell from your generalised description, but I would hazard that what you have written could be categorized as Anemic Domain Model.
I don't think this is a particularly bad approach, nor, if you consider your Poco's as structs does it nescarly break OOP in the more specific sense. In that your Objects are now the LogicClasses. Indeed if you make your Pocos immutable the design could be considered quite Functional.
However, when you reference Shared Logic, Pocos that are almost but not the same and statics I start to worry about the detail of your design.
I've added to my post, essentially copying your example. Sorry ti wasn't clear to start with
– MyDaftQuestions
3 hours ago
1
what I mean is, if you told us what the application does it would be easier to write examples. Instead of LogicClass you could have PaymentProvider or whatever
– Ewan
2 hours ago
add a comment |
If I read your explanation correctly your objects look a bit like this: (tricky without context)
public class LogicClass
{
private ICommandQueryObject cmdQuery;
public PocoA Method(PocoB pocoB) { ... }
}
public class PocoX
{
public string DataA {get;set;}
public int DataB {get;set;}
... etc
}
In that your Poco classes contain only data and your Logic classes contain the methods which act on that data; yes, you have broken the principles of "Classic OOP"
Again, it's hard to tell from your generalised description, but I would hazard that what you have written could be categorized as Anemic Domain Model.
I don't think this is a particularly bad approach, nor, if you consider your Poco's as structs does it nescarly break OOP in the more specific sense. In that your Objects are now the LogicClasses. Indeed if you make your Pocos immutable the design could be considered quite Functional.
However, when you reference Shared Logic, Pocos that are almost but not the same and statics I start to worry about the detail of your design.
I've added to my post, essentially copying your example. Sorry ti wasn't clear to start with
– MyDaftQuestions
3 hours ago
1
what I mean is, if you told us what the application does it would be easier to write examples. Instead of LogicClass you could have PaymentProvider or whatever
– Ewan
2 hours ago
add a comment |
If I read your explanation correctly your objects look a bit like this: (tricky without context)
public class LogicClass
{
private ICommandQueryObject cmdQuery;
public PocoA Method(PocoB pocoB) { ... }
}
public class PocoX
{
public string DataA {get;set;}
public int DataB {get;set;}
... etc
}
In that your Poco classes contain only data and your Logic classes contain the methods which act on that data; yes, you have broken the principles of "Classic OOP"
Again, it's hard to tell from your generalised description, but I would hazard that what you have written could be categorized as Anemic Domain Model.
I don't think this is a particularly bad approach, nor, if you consider your Poco's as structs does it nescarly break OOP in the more specific sense. In that your Objects are now the LogicClasses. Indeed if you make your Pocos immutable the design could be considered quite Functional.
However, when you reference Shared Logic, Pocos that are almost but not the same and statics I start to worry about the detail of your design.
If I read your explanation correctly your objects look a bit like this: (tricky without context)
public class LogicClass
{
private ICommandQueryObject cmdQuery;
public PocoA Method(PocoB pocoB) { ... }
}
public class PocoX
{
public string DataA {get;set;}
public int DataB {get;set;}
... etc
}
In that your Poco classes contain only data and your Logic classes contain the methods which act on that data; yes, you have broken the principles of "Classic OOP"
Again, it's hard to tell from your generalised description, but I would hazard that what you have written could be categorized as Anemic Domain Model.
I don't think this is a particularly bad approach, nor, if you consider your Poco's as structs does it nescarly break OOP in the more specific sense. In that your Objects are now the LogicClasses. Indeed if you make your Pocos immutable the design could be considered quite Functional.
However, when you reference Shared Logic, Pocos that are almost but not the same and statics I start to worry about the detail of your design.
answered 4 hours ago
EwanEwan
42.8k33695
42.8k33695
I've added to my post, essentially copying your example. Sorry ti wasn't clear to start with
– MyDaftQuestions
3 hours ago
1
what I mean is, if you told us what the application does it would be easier to write examples. Instead of LogicClass you could have PaymentProvider or whatever
– Ewan
2 hours ago
add a comment |
I've added to my post, essentially copying your example. Sorry ti wasn't clear to start with
– MyDaftQuestions
3 hours ago
1
what I mean is, if you told us what the application does it would be easier to write examples. Instead of LogicClass you could have PaymentProvider or whatever
– Ewan
2 hours ago
I've added to my post, essentially copying your example. Sorry ti wasn't clear to start with
– MyDaftQuestions
3 hours ago
I've added to my post, essentially copying your example. Sorry ti wasn't clear to start with
– MyDaftQuestions
3 hours ago
1
1
what I mean is, if you told us what the application does it would be easier to write examples. Instead of LogicClass you could have PaymentProvider or whatever
– Ewan
2 hours ago
what I mean is, if you told us what the application does it would be easier to write examples. Instead of LogicClass you could have PaymentProvider or whatever
– Ewan
2 hours ago
add a comment |
Thanks for contributing an answer to Software Engineering Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsoftwareengineering.stackexchange.com%2fquestions%2f389638%2fam-i-breaking-oop-practice-with-this-architecture%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I don't see anything fundamentally wrong with your architecture as you've currently described it.
– Robert Harvey♦
3 hours ago
3
There isn't enough functional detail in your code example to provide any further insight. Foobar examples seldom provide sufficient illustration.
– Robert Harvey♦
3 hours ago