Difference between revisions of "System Architecture"

From Heureka Wiki
Jump to navigation Jump to search
Line 66: Line 66:
 
The system is built with a layered architecture (see for example [[ISBN 0321154959|Bass et al: Software Architecture in Practice]]. The layering is based on the system logic, where each layer adds functionality from a lower layer.
 
The system is built with a layered architecture (see for example [[ISBN 0321154959|Bass et al: Software Architecture in Practice]]. The layering is based on the system logic, where each layer adds functionality from a lower layer.
  
The tree layers are:
+
The three layers are:
  
 
;Application Layer: Each application is a separate subsystem. An application connects the domain specific subsystems into the functionality provided by the application.
 
;Application Layer: Each application is a separate subsystem. An application connects the domain specific subsystems into the functionality provided by the application.
Line 79: Line 79:
  
 
Inside a subsystem, layering by type, i.e. UI -> Logic -> DB should be done (if a subsystem has a presentation and/or persistence service). A subsystem should be able to use the logic of another subsystem without refering to the presentation or persistence service of that subsystem. The persistence service should be encapsulated inside the subsystem and not be used directly by other subsystems. The presentation service of a subsystem should be available for composition of UI.
 
Inside a subsystem, layering by type, i.e. UI -> Logic -> DB should be done (if a subsystem has a presentation and/or persistence service). A subsystem should be able to use the logic of another subsystem without refering to the presentation or persistence service of that subsystem. The persistence service should be encapsulated inside the subsystem and not be used directly by other subsystems. The presentation service of a subsystem should be available for composition of UI.
 +
 +
''Unfortunately the subsystem layering has not always been used, in many cases several subsystems access the same tables in the database directly. Some subsystems are also poorly layered, e.g. with database code inside the UI, or UI code inside the logic.''
 +
 +
=== MVC ===
 +
 +
Linking between user interface and the domain model is done with the architectural pattern Model-View-Controller (Reenskaug 1979).
 +
 +
The model is a domain entity. When the entity is changed, it signals that with an event so that all views rendering the entity can update themselves. The event <tt>PropertyChanged</tt> is used when a property is changed, the interface <tt>IBindingList</tt> is used when a list or collection is changed. In some cases other events are also used, in <tt>Slu.Heureka.BaseLayer.ComponentModel</tt> there are a few more EventArgs that can be used. That namespace also contains the class <tt>ExtendedBindingList</tt> which is recommended for collections that can be bound.
  
''Unfortunately the subsystem layering has not always been used, in many cases several subsystems access the same tables in the database directly. Some subsystems are also poorly layered, e.g. with database code inside the UI, or UI code inside the logic.''
+
The view is any kind of graphical control, such as a TextBox, a DataGrid, a TreeView, or a Map. The view can show and change some parts of the entity.
 +
 
 +
The controller is the object that reacts on user inputs, typically event handlers in a form.
 +
 
 +
When developing with MVC it is important not to short-circuit the view and the controller when they are implemented in the same class. The event handler should only update the model, and not trigger changes in the view directly.  
 +
 
 +
=== Dependency inversion ===
 +
 
 +
 
 +
För att minska beroenden mellan olika delsystem bör de delsystem som behöver en viss typ av tjänst definiera ett interface för den tjänsten. Exempelvis deklarerar delsystemet Forest att det behöver tjänsten IBiomassService för att räkna ut biomassa. Delsystemet Biomass implementerar gränssnittet. På så sätt undviks ett direkt beroende mellan delsystemen.
 +
Klasserna i delsystemet Slu.Heureka.BaseLayer.Services implementerar en enkel service locator.
 +
Funktionaliteten i Services implementerades relativt sent i projektet men har visat sig vara enkel och flexibel. Vid vidareutveckling kan med fördel fler delsystem göras mer oberoende av varandra med hjälp av denna funktionalitet.
 +
=== Persisting Data ====
 +
 
 +
System utnyttjar både filer och relationsdatabaser (SQL Server) för att lagra data.
 +
 +
 +
 +
 +
 +
Samtliga filer lagras som default i användarens dokumentkatalog. På så sätt kan flera användare använda samma dator men ha sina egna inställningar.
 +
Vid lagring i databas används typade dataset och/eller data readers. Vanligtvis används typade dataset för att underhålla informationen men data readers för att snabbt läsa upp informationen under beräkningar etc.
 +
Lagring i filer sker i stor omfattning genom serialisering av objekt. Enklare inställningar lagras och läses genom klassen ConfigurationStore. För styrtabeller används en hjälpklass för serialisering så att kod för serialisering inte behöver implementeras i varje styrtabell.
 +
Serialisering har visat sig vara ett mindre lyckat designval eftersom det försvårar refactoring. På sikt bör serialisering byggas bort från systemet. ConfigurationStore och serialiseringen av styrtabeller fungerar däremot bra.
 +
=== Error Handling ===
 +
När någon typ av fel upptäcks ska ett exception kastas. Inbyggda exceptions ska användas om de passar (till exempel ArgumentException, ArgumentNullException och InvalidOperationException). I annat fall används egna exceptions som ska ärva från ApplicationException.
 +
Man bör undvika att kod är beroende av exceptions i det normala flödet. Ska man till exempel validera om en sträng innehåller ett giltigt nummer ska man använda int.TryParse(), inte int.Parse() eftersom den sistnämnda ger ett exception om strängen inte är numerisk.
 +
Behöver man fånga exceptions för att göra någon speciell återhämtning ska man bara fånga det specifika exception man vill återhämta sig från.
 +
I användargränssnittet bör det finnas exception-hanterare som fångar alla fel från anropad kod och visar lämpligt felmeddelande till användaren. Använd Slu.Heureka.BaseLayer.HeurekaForms.ErrorDialog för att visa felmeddelandet.
 +
Förklaringarna i felmeddelandena bör vara ganska kortfattade. Behövs en längre förklaring, ange HelpLink i det exception som kastas.
 +
=== Kommandon ===
 +
Design-mönstret Command används för att kapsla in åtgärder användaren utför i egna objekt.
 +
Genom att använda Command uppnås flera fördelar:
 +
 +
, formulären blir därmed enklare.
 +
 +
 
 +
=== Reports ===
 +
 
 +
Standrd reports are developed in Visual Studio as Microsoft Client Report Definitions (rdlc). These are shown in the applications with the <tt>ReportViewer/<tt> component.
 +
=== Help ====
 +
 
 +
The applications should have support for online help.
  
 
== Technical Environment ==
 
== Technical Environment ==

Revision as of 11:19, 20 May 2010