soa - Refactoring God objects in WCF services -


we came across god object in our system. system consists of public service exposed our clients, middle office service , back office service.

the flow following: user registers transaction in public service, manager middle office service checks transaction , approves or declines transaction , manager back office service finalizes or declines transaction.

i'am using word transaction, in reality different types of operations crud on entity1, crud on entiny2... not crud operations many other operations approve/send/decline entity1, make entity1 parent/child of entity2 etc etc...

now wcf service contracts separated according parts of system. have 3 service contracts:

publicservice.cs middleofficeservice.cs backofficeservice.cs 

and huge amount of operation contracts in each:

public interface ibackofficeservice {     [operationcontract]     void addentity1(entity1 item);      [operationcontract]     void deleteentity1(entity1 item);      ....      [operationcontract]     void sendentity2(entity2 item);      .... } 

the number of operation contracts 2000 across 3 services , approximately 600 per each service contract. not breaking best practices, huge pain update service references takes ages. , system growing each day , more , more operations added services in each iteration.

and facing dilemma how can split god services logical parts. 1 says service should not contain more 12~20 operations. others different things. realize there no golden rule, wish hear recommendations this.

for example if split services per entity type can 50 service endpoints , 50 service reference in projects. maintainability in case?

one more thing consider. suppose choose approach split services per entity. example:

public interface ientity1service {     [operationcontract]     void addentity1(entity1 item);      [operationcontract]     void approveentity1(entity1 item);      [operationcontract]     void sendentity1(entity1 item);      [operationcontract]     void deleteentity1(entity1 item);     ....      [operationcontract]     void finalizeentity1(entity1 item);      [operationcontract]     void declineentity1(entity1 item); } 

now happens should add reference service both in public client , back office client. back office needs finalizeentity1 , declineentity1 operations. here classic violation of interface segregation principle in solid. have split further may 3 distinct services ientity1frontservice, ientity1middleservice, ientity1backservice.

the challenge here refactor code without changing large portions of avoid potential regressions.

one solution avoid large business code thousands of lines split interfaces/implementations multiple parts, each part representing given business domain.

for instance, ipublicservice interface written follows (using interface inheritance, one interface each business domain):

ipublicservice.cs:

[servicecontract] public interface ipublicservice : ipublicservicedomain1, ipublicservicedomain2 { } 

ipublicservicedomain1.cs:

[servicecontract] public interface ipublicservicedomain1 {     [operationcontract]     string getentity1(int value); } 

ipublicservicedomain2.cs:

[servicecontract] public interface ipublicservicedomain2 {     [operationcontract]     string getentity2(int value); } 

now service implementation, split multiple parts using partial classes (one partial class each business domain):

service.cs:

public partial class service : ipublicservice { } 

service.domain1.cs:

public partial class service : ipublicservicedomain1 {     public string getentity1(int value)     {         // implementation     } } 

service.domain2.cs:

public partial class service : ipublicservicedomain2 {     public string getentity2(int value)     {         // implementation     } } 

for server configuration, there still 1 endpoint:

<system.servicemodel>   <services>     <service name="wcfservicelibrary2.service">       <endpoint address="" binding="basichttpbinding" contract="wcfservicelibrary2.ipublicservice">         <identity>           <dns value="localhost" />         </identity>       </endpoint>       <endpoint address="mex" binding="mexhttpbinding" contract="imetadataexchange" />       <host>         <baseaddresses>           <add baseaddress="http://localhost:8733/design_time_addresses/wcfservicelibrary2/service1/" />         </baseaddresses>       </host>     </service>   </services>   <behaviors>     <servicebehaviors>       <behavior>         <servicemetadata httpgetenabled="true" httpsgetenabled="true" />         <servicedebug includeexceptiondetailinfaults="false" />       </behavior>     </servicebehaviors>   </behaviors> </system.servicemodel> 

same client: still 1 service reference:

<system.servicemodel>   <bindings>     <basichttpbinding>       <binding name="basichttpbinding_ipublicservice" />     </basichttpbinding>   </bindings>   <client>     <endpoint address="http://localhost:8733/design_time_addresses/wcfservicelibrary2/service1/"       binding="basichttpbinding" bindingconfiguration="basichttpbinding_ipublicservice"       contract="servicereference1.ipublicservice" name="basichttpbinding_ipublicservice" />   </client> </system.servicemodel> 

this allows refactor server side splitting huge services multiple logical parts (each part associated given business domain).

this doesn't change fact each of 3 services still has 600 operations, client proxy generation still take ages. @ least code better organized server-side, , refactoring cheap , not-so-risky.

there no silver-bullet here, code reorganization better readability/maintenance.

200 services 10 operations each vs 20 services 100 operations each topic, sure refactoring require way more time, and still have 2000 operations. unless refactor whole application , reduce number (for instance providing services more "high-level" (not possible)).


Comments

Popular posts from this blog

How has firefox/gecko HTML+CSS rendering changed in version 38? -

javascript - Complex json ng-repeat -

jquery - Cloning of rows and columns from the old table into the new with colSpan and rowSpan -