Enterprise Component Authoring Principles and Design Patterns
Transcription
Enterprise Component Authoring Principles and Design Patterns
Enterprise Component Authoring Principles and Design Patterns Authors NS Nagaraj, Srinivas Thonse, Naqvi, Mukulika Members, Comfactory Group Software Engineering and Technology Labs Infosys Technologies Limited Bangalore Abstract Object technology has evolved over many years yielding various design principles, languages and environments producing a productive way of writing complex, large applications. The introduction of COMponent models has eased the complexities of developing distributed applications. The DNA model has evolved as the de-facto reference architecture for enterprise applications. Enterprise component developers have languages and environments that support both the idea of classes/objects and components. Classes and components are two good constructs available, which when used rightly produces software that is scalable, reusable and maintainable. Give the enterprise need to develop applications for business process automation, it is important for organizations to understand and evolve component authoring principles and patterns. These should provide a reference standard for authoring components. With our experience in constructing various large enterprise applications on DNA (for Insurance, payroll, e-store), we have devised a set of principles and patterns that occur quite often in enterprise solutions. 1. Component Granularity Principle (CGP) proposes a way to decide granularity of components. 2. Lazy Construction of Components (LCC) proposes a useful design idea to deal with User Interfaces that require large business objects from enterprise application servers. 3. Business Object Editor Pattern: Enterprise applications often require User Interface components for configuring and editing of business objects by operators. This pattern is useful to design such components. 4. Lite-client and Worker Pattern (LCW) proposes a technique to improve the maintainability of client-side components of n-tier applications. This is accomplished by minimizing dependency of User Interface components on finegrained Business Objects. ©2000 Infosys All rights reserved. 1 1 Component Granularity Principle Consider a simple order processing enterprise application, which provides interface for accepting and processing of orders from users items from users. Let us say this system needs to collect 1000 orders every minute and look at the fulfillment possibility. If the order cannot be fulfilled then system will put this on back order list and process later (on availability of inventory). From the application design angle what would you model as Component/Classes? If you examine the typical Order processing abstraction there are many elements like item details, customer address, price details, shipment information, payment details, Order processor. If you model all the above abstractions as components then it will result as overengineered system with too many component instances leading to inefficient usage of system resources (Imagine an Order containing 1000 Item components, in a peak minute system will end up creating more than 1 million components). Now the question is what should be Component and what should be Class? Principle “Fine grain Business Entities should be modeled using Class construct, Business Services should be modeled using Component construct” Applying this principle Order processing system will lead to Business entities modeled as Classes named Order, Item, Shipment, Address, Payment and Business Services modeled as Components named OrderProcessor, ShipmentProcessor and Payment Processor. This results in fewer components and optima l use of system resources. ©2000 Infosys All rights reserved. 2 2 Lazy construction of Components 2.1 Context Enterprise applications have user interfaces made of text fields, radio buttons, check boxes, selection lists, etc., that map to attributes of the business object being edited, e.g. Customer, or, attributes of input required for business tasks such as approve leave. Many attributes of business objects are references or identifiers for static data such as country codes, state codes and other business-specific codes. For e.g., Customer object might have fields such as name, address and countryCode. Among these fields, countryCode refers to a country in the country code data space. The User interface needs to provide lists of such codes in combo boxes. A screen could contain many such fields such as Country, States, Currency and so on. The user interface requires that these lists be fetched and populated in the combo boxes. Bringing up a form containing a large number of such lists would take significant time in fetching the lists and populating the fields. Some business objects are composites of other smaller business objects. Screens meant for editing such business objects (“composite screens”) typically have several tabs, where each tab shows data of one or a few of these contained objects. This requires a solution to construct the screen in minimum time. 2.2 Solution To reduce the initial time taken by the UI screen to load, we have adopted the technique of lazy construction of components. The concept here is to fetch as little data as needed before popping up the screen and to fetch the rest only as needed. This means that all the combo-boxes are populated when the user clicks on a combo box for the first time. In the case of composite screens, data shown in one or a few tabs are fetched initially. Below a design for building such components is described. 2.2.1 Static list in Combo box The policy for loading static data in the combo box is as follows: The combo boxes are not filled with any data to start with, i.e. when the screen pops up, the combo boxes is empty. When the user clicks on a combo box the data records pertaining to that field are fetched in an object and also saved in a file in the local system. This cached static data is marked with a time stamp. Every time, on the first click on the combo box, a time stamp comparison is made between the cached data on the local disk and that in the database on the server side. If the cached data is found to be stale than the server data, the data is fetched from the server database; otherwise the cac hed data is used. Moreover, the timestamp check and, if needed, the fetching of data is accomplished in just one call to the server side. Below is the class design of the “static data access component”. Static data access component: ListObject: This class contains data for a code type and for a key for e.g. the code type could be state codes and key could be India. So the Recordset would contain records for all the stated in India. StaticDataLoader: The StaticDataLoader class is responsible for constructing the ListObject class and populate it with data. It uses the classes ©2000 Infosys All rights reserved. 3 StaticDataCacheManager and StaticDataInterface to get the latest data either from the cache or from the server. StaticDataCacheManager: This class is used to cache the static code data retrieved from the server. StaticDataInterface: This class is a COM component. This is used to get the static codes data from the server. Class Diagram ListObject dataRS : RecordSet getNext() getRecordCount() validateCode() uses to populate combo boxes creates and populates UI Screen static data interface StaticDataLoader for data from server getListObject() <<COM Component>> StaticDataInterface getStaticCodes() uses for loading cached data StaticDataCacheMana ger getUpdateTime() getStaticCodes() updateStaticCodes() Sequence Diagram: Populating Combo boxes ©2000 Infosys All rights reserved. 4 The sequence starts when a user clicks on a combo box on the screen. : UI Screen : StaticDataLoader : ListObject : StaticDataCacheManager : StaticDataInterface getListObject(String, List<String>) getUpdateTime(String) getStaticCodes(String, List<String>, String) check the return value of getStaticCodes() getStaticCodes(String, List<String>) Called based on the check performed. i.e. if cache is found to be up to date. construct() getRecordCount( ) getNext( ) 2.3 Repeated calls to populate combo box. Impact The above design mechanism for displaying static data in the user interfaces will result in the reduction in time of the initial loading. However, this wait time is not completely eliminated but distributed across various user events like combo box clicking. In many cases, it might be desired that the combo boxes be filled on loading itself; or that some combo boxes be filled and some not. This mechanism is meant for reducing the initial load time of the screen. However in both the cases, i.e. immediate and lazy loading, the caching mechanism provided by the StaticDataCacheManager can be used. ©2000 Infosys All rights reserved. 5 3 Business Object Editor Pattern 3.1 Context 3.2 Solution Most of the enterprise applications require some kind of editors to add, delete, edit or search business objects such as Customer, Country and Currency. Generally for any Business object the editor provides the same set of functionalities like add, delete, edit, search but the object properties that are displayed differ from object to object. For e.g., the Business Object Editor for Customer or Equipment will have the same set of functionalities but the properties of Customer are different from that of Equipment. Thus we see a definite pattern can be followed to provide these functionalities, the only difference will be the forms and the data. For any business object editor, we can design the user interface to have a Master or parent form that will have 1. Searcher part to specify the search criteria and search fields 2. An object list satisfying the search criteria 3. Option to add, edit, delete the selected object and save the changes in the database. When an object is selected for editing or deleting, or a new object has to be added, a child form comes up with all the details of the business object. The child form should have ok, next and previous options. a. On ok click it saves the changes made to the selected object. b. On next or previous click it not only saves the changes but also displays the details of next or previous object in the object list in the Parent form. All these changes are saved locally c. On save click, the changes are saved to the server. Snapshots of Customer business object editor are given below. ©2000 Infosys All rights reserved. 6 ©2000 Infosys All rights reserved. 7 3.2.1 Class Design <<Interface>> IView IFormViewInteractor oldObject newObject viewInteractor addObject() nextObject() prevObject() selectedObject() inFirstObject() changeObject() clearAll() setAllFields() getparentView() IMasterForm search() save() clear() ViewInteractor CustomerChildForm CustomerMasterForm Apply() PrevObject() NextObject() 1..1 1..1 CustomerMasterDirectory search() save() IView interface is implemented by the Master Form to interact with the Child form through the ViewInteractor class. IMasterForm interface is implemented by the Master Form to interact with it’s MasterDirectory class to search and save business objects in the database. IFormViewInteractor interface is implemented by the Child Form to interact with the Master Form through the ViewInteractor class. ?? OldObject stores the object passed to the child form for change. It is NULL for add mode. ?? NewObject gets populated with changed data on add , next or previous click. MasterDirectory is implemented by every Business Object differently (e.g.. CustomerDirectory, EquipmentDirectory) to save and search different data from the database. The search , save methods of this class are called by the Master Forms. Although the implementation is different for different business objects the pattern followed is the same. The ViewInteractor class is used to interact between Master and child forms. It has a reference to IFormViewInteractor interface of the child form as well as the IView ©2000 Infosys All rights reserved. 8 interface of the parent form. All interactions between child and parent form take place through this class. It has the following functions ?? Apply If the oldObject from child form is NULL i.e it is in add mode Call ParentForm.addObject with the newObject Else if child form has an oldObject i.e it is in edit mode Call ParentForm.changeObject with newObject Endif ?? NextObject Call Apply Get the nextObject from parent form Assign it to oldObject of childForm Populate child form with the values in oldObject ?? PreviousObject Call Apply Get the previousObject from parent Form Assign it to oldObject of childForm Populate child form with the values in oldObject If the object selected is the first object in the object list of parent form then Disable previous button Endif 3.2.2 Interaction between the Master and Child Forms ?? When Add/Edit clicked in Master Form ©2000 Infosys All rights reserved. 9 : Customer MasterForm : Customer ChildForm CustomerMaster FormView : IView : View Interactor : User IView Interface of Master Form , add/edit mode and whether first object selected ,is passed to the child form. Clicks add/edit Load oldObject=selectedObject( ) bFirstObject=inFirstObject( ) Populate(oldObject) Child form is populated if in edit mode new OldObject will be NULL for add mode Enabling, disabling of previous button depends on this boolean IFormView Interactor interface of child form is passed to the ViewInteractor class ?? When Ok/Prev/Next clicked in Child Form ©2000 Infosys All rights reserved. 10 : Customer ChildForm : View Interactor : User Ok/Prev/Next button click Populate newObject with field values Apply( ) 1.Apply() is called for Ok click 2.PrevObject() is called for Prev click 3.NextObject() is called for Next click 3.3 Impact This pattern through mandating the use of interfaces brings about uniformity in the user interface components. Repeated use of the classes and interfaces leads to significant reuse of code, increased reliability and faster development. Code will be less error prone and easier to maintain. ©2000 Infosys All rights reserved. 11 4 Lite Client and Worker pattern 4.1 Context The client-side components of Enterprise Applications contain many invocations of services from Server-side components. If the services are very large in number, the compile-time dependencies of client components on server components become very difficult to maintain. This leads to deployment issues during maintenance and upgrades. 4.2 Solution LCW pattern is a way to decouple the client and server to a large extent. The requests for services are modeled as documents. The application server hosts components called “Workers” which implement the processing function. The clients request WorkerFactory for desired Workers by specifying the name of the worker object. The WorkerFactory instantiates the required Worker object implementation and returns a reference to the instance. The clients then prepare a request object containing the request name and related information and invoke the processing function on the worker instance. The worker instance performs the necessary processing. <<Interface>> IWorker execute(WorkRequest : Document) <<Document>> WorkRequest WorkerFactory <<implements>> createWorker(name : string) : IWorker set(name : String, number : integer) getAsInt(name : string) : integer set(name : string, value : string) getAsString(name : string) : string OrderProcessorWorker creates execute(action : WorkRequest) ©2000 Infosys All rights reserved. 12 UI : User 1: submit : Worker Factory : Order Processor work : Work Request 2: createWorker("ÖrderProcessor") 3: new( ) 4: new( ) 5: set("RequestName", "Process Order") 6: set("name", "Smith") 7: set("item", ïtemName) 8: set("cardNum", crNo) 9: execute(work) 4.3 Impact This pattern completely simplifies client-side programming. All the clients know about is about names of Worker objects and the request contents required. If this can be standardized (“contract”) at the start of the project, the user interface development can run independent of server-side development. It becomes easy to manage change when new versions of worker classes are released, through adding request translation functions that transparently translate the request objects to the new semantics. On the flip side, this adds an extra layer of indirection and requires strict adherence of the contracts – more care by developers may be required. ©2000 Infosys All rights reserved. 13