Skip to main content
Elaborated more on the interface approaches
Source Link

Having over-engineered one or two systems in my career, I will try to answer this from a pragmatic point of view.

My first approach would be to establish the convention, that data must not be modified in the presentation layer. If you work alone you know your own conventions anyway. In a small team you should be able to communicate them easily. Yes, this does not prevent violations at compile time, but unintentional violations should be rare and easy to spot (call hierarchy of a certain setter, for example).

If you absolutely need/want to implement this rule in code, putting the controllers and their respective data objects into a single package each, is the next best thing. Also I would not use protected, but default/package scope (i.e. omit the visibility keyword). Of the three options you presented, this is the most light weight (and therefore best maintainable and scalable) approach. You shouldn't be too worried about "...making it to difficult to expand the program.", you mereley have to live with potentially a lot of classes in one package. Maybe you can mitigate this by cleverly grouping certain controllers with some objects into their own package.

If this approach also fails, immutable objects are what you want. You could implement them plain (constructor and copy constructor, no setters), with factories/factory methods, or even use the Builder Pattern. Just keep in mind, that the overhead (i.e. boiler plate code) increases significantly with this solution and you should ask yourself if the gain (less time spent hunting/fixing bugs) is really greater than the cost (writing, testing and maintaining boiler plate code). In fact I would only recommend this solution if you can guarantee, that the objects never need to be modified, and therefore you can ditch the copy code. This does not seem to be the case for your example, though.

I predict thatIntroducing a special getter-interface for each(!) data-class means more overhead than protected/default setters and is only half as strict, as you mentioned yourself: One could always downcast to the actual data-class. To improve this, you could give your two interface based solutions end updata-classes protected or package visibility and put them in the same package as the controllers, but then you are back at square one, with additional interfaces and complexity.

Keeping the controllers and the data-model separated is a maintenance nightmaregood idea. For most applications the model is much more likely to change than the controller logic. And you want to keep that changing part contained, since every interface change potentially introduces a bug and means additional adaptations in the test- and client code. By moving and/or wrapping the getters directly into the controller (with or without special interfaces) you now havealso increase the scope of the change. You'd suddenly need to maintain and potentiallythe test several files- and client code of the controller, instead of just the model, if you want to add/change one field. I do not recommend them at all Another, simpler problem is, if you need a collection of non-primitive data in your model.

Any software design decision boils down to the question of which solution lets you, your colleagues and users work most efficiently. These three groups will likely have contradictory needs and so it is hard to find the absolutely best solution and trade-offs are almost always a part of it.

Having over-engineered one or two systems in my career, I will try to answer this from a pragmatic point of view.

My first approach would be to establish the convention, that data must not be modified in the presentation layer. If you work alone you know your own conventions anyway. In a small team you should be able to communicate them easily. Yes, this does not prevent violations at compile time, but unintentional violations should be rare and easy to spot (call hierarchy of a certain setter, for example).

If you absolutely need/want to implement this rule in code, putting the controllers and their respective data objects into a single package each, is the next best thing. Also I would not use protected, but default/package scope (i.e. omit the visibility keyword). Of the three options you presented, this is the most light weight (and therefore best maintainable and scalable) approach. You shouldn't be too worried about "...making it to difficult to expand the program.", you mereley have to live with potentially a lot of classes in one package. Maybe you can mitigate this by cleverly grouping certain controllers with some objects into their own package.

If this approach also fails, immutable objects are what you want. You could implement them plain (constructor and copy constructor, no setters), with factories/factory methods, or even use the Builder Pattern. Just keep in mind, that the overhead (i.e. boiler plate code) increases significantly with this solution and you should ask yourself if the gain (less time spent hunting/fixing bugs) is really greater than the cost (writing, testing and maintaining boiler plate code). In fact I would only recommend this solution if you can guarantee, that the objects never need to be modified, and therefore you can ditch the copy code. This does not seem to be the case for your example, though.

I predict that your two interface based solutions end up in a maintenance nightmare. For every interface change you now have to maintain and potentially test several files instead of one. I do not recommend them at all.

Any software design decision boils down to the question of which solution lets you, your colleagues and users work most efficiently. These three groups will likely have contradictory needs and so it is hard to find the absolutely best solution and trade-offs are almost always a part of it.

Having over-engineered one or two systems in my career, I will try to answer this from a pragmatic point of view.

My first approach would be to establish the convention, that data must not be modified in the presentation layer. If you work alone you know your own conventions anyway. In a small team you should be able to communicate them easily. Yes, this does not prevent violations at compile time, but unintentional violations should be rare and easy to spot (call hierarchy of a certain setter, for example).

If you absolutely need/want to implement this rule in code, putting the controllers and their respective data objects into a single package each, is the next best thing. Also I would not use protected, but default/package scope (i.e. omit the visibility keyword). Of the three options you presented, this is the most light weight (and therefore best maintainable and scalable) approach. You shouldn't be too worried about "...making it to difficult to expand the program.", you mereley have to live with potentially a lot of classes in one package. Maybe you can mitigate this by cleverly grouping certain controllers with some objects into their own package.

If this approach also fails, immutable objects are what you want. You could implement them plain (constructor and copy constructor, no setters), with factories/factory methods, or even use the Builder Pattern. Just keep in mind, that the overhead (i.e. boiler plate code) increases significantly with this solution and you should ask yourself if the gain (less time spent hunting/fixing bugs) is really greater than the cost (writing, testing and maintaining boiler plate code). In fact I would only recommend this solution if you can guarantee, that the objects never need to be modified, and therefore you can ditch the copy code. This does not seem to be the case for your example, though.

Introducing a special getter-interface for each(!) data-class means more overhead than protected/default setters and is only half as strict, as you mentioned yourself: One could always downcast to the actual data-class. To improve this, you could give your data-classes protected or package visibility and put them in the same package as the controllers, but then you are back at square one, with additional interfaces and complexity.

Keeping the controllers and the data-model separated is a good idea. For most applications the model is much more likely to change than the controller logic. And you want to keep that changing part contained, since every change potentially introduces a bug and means additional adaptations in the test- and client code. By moving and/or wrapping the getters directly into the controller (with or without special interfaces) you also increase the scope of the change. You'd suddenly need to maintain the test- and client code of the controller, instead of just the model, if you want to add/change one field. Another, simpler problem is, if you need a collection of non-primitive data in your model.

Any software design decision boils down to the question of which solution lets you, your colleagues and users work most efficiently. These three groups will likely have contradictory needs and so it is hard to find the absolutely best solution and trade-offs are almost always a part of it.

Source Link

Having over-engineered one or two systems in my career, I will try to answer this from a pragmatic point of view.

My first approach would be to establish the convention, that data must not be modified in the presentation layer. If you work alone you know your own conventions anyway. In a small team you should be able to communicate them easily. Yes, this does not prevent violations at compile time, but unintentional violations should be rare and easy to spot (call hierarchy of a certain setter, for example).

If you absolutely need/want to implement this rule in code, putting the controllers and their respective data objects into a single package each, is the next best thing. Also I would not use protected, but default/package scope (i.e. omit the visibility keyword). Of the three options you presented, this is the most light weight (and therefore best maintainable and scalable) approach. You shouldn't be too worried about "...making it to difficult to expand the program.", you mereley have to live with potentially a lot of classes in one package. Maybe you can mitigate this by cleverly grouping certain controllers with some objects into their own package.

If this approach also fails, immutable objects are what you want. You could implement them plain (constructor and copy constructor, no setters), with factories/factory methods, or even use the Builder Pattern. Just keep in mind, that the overhead (i.e. boiler plate code) increases significantly with this solution and you should ask yourself if the gain (less time spent hunting/fixing bugs) is really greater than the cost (writing, testing and maintaining boiler plate code). In fact I would only recommend this solution if you can guarantee, that the objects never need to be modified, and therefore you can ditch the copy code. This does not seem to be the case for your example, though.

I predict that your two interface based solutions end up in a maintenance nightmare. For every interface change you now have to maintain and potentially test several files instead of one. I do not recommend them at all.

Any software design decision boils down to the question of which solution lets you, your colleagues and users work most efficiently. These three groups will likely have contradictory needs and so it is hard to find the absolutely best solution and trade-offs are almost always a part of it.