Continuation from last post:
I think now that my reading of Rickards post perhaps was too restrictive.
If the "tell, don't ask" type of search functionality resides in the
application layer that's distinct from a service layer it's seems we're
describing pretty much the same thing (but a simple Mediator is of cource a lot
less qualified than the Qi4J stuff discussed here...)
/Niklas
2009-03-12 Rickard Öberg wrote:
Hey,
>
>So, yesterday I tried reworking my StreamFlow workflow app into using
>the hexagonal architecture. So far I am extremely happy with the
>results. One of the things I have had big trouble with before is to
>implement the "TellDontAsk" principle. It seemed like no matter what I
>did I had to, in the end, ask for model information in various ways,
>thus showing all the inner details that I had been trying to encapsulate
>with my private mixins etc.
>
>With the hexagonal architecture, where UI can be "at the bottom", and
>considered "output", this problem went away. Let me give you an example.
>In the app there is a search field and a search result view. In a normal
>layered app there would be a UI component that takes the search string
>and sends it to the application layer, and then presents the results.
>The app layer would have a method like this:
>SearchResult search(String query);
>
>This is very problematic though: first of all the search field has to
>know about the search result view, so they are coupled. If I then also
>want to update some other part in the UI the search field has to know
>about this too. Also, it is highly likely that once I get the result, I
>have to query the application for other things in order to present the
>result.
>
>With hexagonal architecture this mess goes away. Since the flow is only
>"in->out" rather than "up-down-up", the application layer method becomes:
>void search(String query);
>The application layer performs the query. When it is done it then simply
>looks up all services that implement SearchObserver, iterates over them,
>and pass the result to them. This can be easily done with a SideEffect
>of the search method, and gives a good example of when to use
>SideEffects. The code is something like this in the SideEffect:
>@Service Iterable observers;
>@This Searcher searcher.
>public void search(String query)
>{
> for(SearchObserver observer: observers)
> {
> observer.refresh(searcher.searchResult().get());
> }
>}
>---
>Since the app layer uses() the UI layer, one of the observers just
>happens to be the search result view, which presents the results. If
>there had been a status bar it could have also consumed the results and
>showed a message like "Found 14 matches". Or more like, a SearchStatus
>service would have Observed the search results, which would have
>produced the string, which is then in turn sent to StatusObservers, one
>of which happens to be the status bar.
>
>If the search takes a long time, the UI would be in trouble with the
>first method, as it would essentially freeze when calling search. With
>hexagonal architecture the search(string) method can accept the string,
>return immediately, and then spawn off an asynchronous search that only
>when completed notifies the observers. The time between search and
>result can be quite long, but the UI will still be responsive in
>between, without the UI having to do the thread trickery. When consuming
>the results the UI does, however, have to ensure that it is on the Swing
>thread.
>
>In any case, a key point is that the search field *does not have to
>know* how to present the results. All it does is take the string and
>send it to the application for querying. What happens then is up to the
>application and observers of the model that the processing changes.
>Input and output are separated in code, but still both are presented on
>the UI screen.
>
>In this way there *is only TELL*, no ask. All events come from the
>outside, goes to the inside (through app->domain), and then goes out
>again. And sometimes the initiator (UI) just happens to be the output too.
>
>This would also simplify testing, as the call to the app and
>introspection of the resulting model using a mock observer is quite easy
>to do.
>
>NEAT!
>
>/Rickard
>
>
>_______________________________________________
>qi4j-dev mailing list
>[email protected]
>http://lists.ops4j.org/mailman/listinfo/qi4j-dev
>
>_______________________________________________
qi4j-dev mailing list
[email protected]
http://lists.ops4j.org/mailman/listinfo/qi4j-dev