Closed
Description
Why not to put exceptions from the data layer into domain layer and make them as a part of business logic? In that case the presentation layer will be completely separated from the data layer: now the ErrorMessageFactory class uses NetworkConnectionException and UserNotFoundException from the data layer.
Activity
[-]Why not to put exceptions from the data layer in domain layer?[/-][+]Why not to put exceptions from the data layer into domain layer?[/+]Trikke commentedon Apr 22, 2016
Because those exceptions belong there. An exception like, for example, "CacheKeyMissingException" should reside in the same layer that it is used, ie: data layer. The exception "ButtonTextEmptyException" is obviously related to ui, so it belongs in the presentation layer. Keep exceptions where they belong. Exceptions are not part of any "logic", nor should be used as a control flow. Also, because the way this project is set up, you need one "entry point" to start the app and know about all the code, and in this case, this is the presentation layer.
I suspect your question pops up because "Exception Handling" is more of a cross-cutting concern, as it something that touches all the layers, but is not exclusively part of one layer.
So each layer has specific tasks related to "Exception Handling".
So, let's imagine an app where i can order a puppy with the press of a button. I press the button, but i'm on a train driving through a tunnel. I'll press the button, Presentation notifies Business of said press. Business logs "Trikke wants a puppy" via Data in a file. Business call Data to make a request to the API and order a puppy. I'm in a tunnel, so the network request fails miserably after a timeout. Data catches this and notifies Business with a general "ApiNotAvailableException". Business notices and removes the log "Trikke wants a puppy". Business notifies Presentation that an unrecoverable error has happened. Presentation shows me a nice messages stating "We couldn't order you a puppy because the app is experiencing network troubles".
And now we've seen a round trip of an action and each layer is doing it's own part in handeling an error in this action.
risayew commentedon Apr 22, 2016
@Trikke, In your example the "ApiNotAvailableException" will be converted to "We couldn't order you a puppy because the app is experiencing network troubles" message in the presentation layer? (in that case "ApiNotAvailableException" is a property of data layer, but the presentation layer has to know about that exception). Is it ok in terms of layered architecture?
Trikke commentedon Apr 22, 2016
Please read up on my other comments on another question about layering. It's a bit of a hard concept, because layering in this project's setup != layers in Clean Architecture. Parts of both the data and presentation layer of this project's setup exist on the same layer in Clean Architecture, so there are no dependency issues.
@android10 has set the project up like this due to a number of advantages, and it is both easier to explain the concept of Clean Architecture and enforce the rules. But i could make a repo with only one project module and have everything in the same namespace and still have a correct architecture in accordance to Clean Architecture. It would just be harder to enforce the rules, i would have more of a mental challenge to respect the boundaries.
risayew commentedon Apr 22, 2016
@Trikke, could you help me, please, to place the things in the right way in some specific scenario? :-)
How to provide an exception to the Presentation and which exception. Because on one hand, there is an "PrimaryKeyException" from database framework, which will be thrown if we will try to add the puppy into database. On the other hand we can define our custom "PuppyAlreadyExist" exception in the data, and throw it before we cache the puppy in the database(simply call subscrier.onError if the puppy was already cached).
Trikke commentedon Apr 22, 2016
Like i said, the "Exception Handling" part of the data layer consist of shielding the app from any problems of external sources (SQL, File storage, Network, ...) which all each have their own set of exceptions and/or problems.
This would mean that indeed, you would create a "PuppyAlreadyExistException" which the data layer throws whenever this scenario happens. Which could be "PrimaryKeyException" in an DB scenario, or "AlreadyInMemoryException" if you would happen to use a MemCache. Maybe you could be using both, first MemCache and then DB, so you catch both exceptions as a "PuppyAlreadyExistException" because they are both the same scenario.
So the presentation layer gets the general "PuppyAlreadyExistException", but not some specific "PrimaryKeyException".
risayew commentedon Apr 22, 2016
@Trikke, thank you for your help!