|
June 2006
June 30, 2006
IASA
Earlier this week I had a meeting with few architects from Israel and we had a conference call (well, sort of, there were a lot of technical problems) with Paul Preiss, president of International Association of Software Architects (IASA). The purpose of the meeting was to discuss forming an IASA chapter in Israel.
The reason I am telling you this is that IASA was formed to deal with issues that matters to architects: (quoted from www.iasahome.org)
- Experience isn't portable: every employer defines and uses architecture differently, sometimes making our experience almost useless when changing companies.
- Resources are scarce: architects have very few resources (content and education) to work with. It is often very difficult to find the materials we need to do our jobs.
- Difficult to judge quality: very few people agree on the fundamental components of architecture or what it takes to become a qualified architect. Without a dependable internal forum we cannot hope to achieve quality architectures.
- Lack of community: there is no way to quickly find peers of our own caliber to discuss the issues which drive us.
Membership is free and considering the other software architects organization (WWISA) has been brain dead for quite some time now, I think it is important for software architects that care about their profession to join in and help make a difference.
Posted by Arnon Rotem-Gal-Oz at 05:44 AM Permalink
|
June 27, 2006
Architecture Dilemmas: O/R Mapping Why/When (Part IV)
Okay, I wasn't planning on having a Part IV of my series on "Architecture Dilemmas:O/R Mapping." (Part I, Part II, and Part III are available here. In addition, a single PDF file is also available.)
What prompted Part IV was my reading Ted Neward's blog on why he thinks O/R mapping is The Vietnam Of Computer Science. If you manage to read over the Vietnam history, Ted makes some interesting point on the problems of O/R Mapping. I tend to agree with most of them; in fact, I mentioned most of them as well (though maybe not as eloquently). It is also interesting in the light that I spent about two hours yesterday debating some of these issues in a meeting with several other architects.
Toward the end of the article Ted offers the following solutions:
- Abandonment.
- Wholehearted acceptance. (move to an OODBMS)
- Manual mapping. (write code by hand - iBATis would fall here as well)
- Acceptance of O/R-M limitations. get the X% (50%,80% whatever) you can get out of O/R mapping
- Integration of relational concepts into the languages. (e.g. LinQ)
- Integration of relational concepts into frameworks. (embedded data-rows/data sets etc in classes to hold data, use typed data sets as well)
Ted recommends going with solution #1 or in his words "...Worse, it is a quagmire that is simply too attractive to pass up, a Siren song that continues to draw development teams from all sizes of corporations (including those at Microsoft, IBM, Oracle, and Sun, to name a few) against the rocks, with spectacular results. Lash yourself to the mast if you wish to hear the song, but let the sailors row."
The way I see it "Computer Science" now has more than 10 years of experience with O/R mapping technologies and the limitations of O/R mapping are well noted. In fact, the good O/R mappers "Accept O/R limitations" (#4 above) and provide mechanisms to by go directly at the data or provide hints for the database etc. And as I said in Part III there are situations where O/R mapping is not the best fit (e.g. reporting), but as someone at the meeting yesterday said, if you have serious reporting needs you would probably have a separate database (e.g. Datamart) just for that.
I think Ted is too quick to forgo the savings of O/R mapping (those X percentile of code you don't need to write, the fact that you externalize the data model from your code etc.) and the fact that for many problems (yes, these are "just" the simple ones, but how many times all of y our application is complicated) O/R mapping will be sufficiently good out of the box--which is,by the way, exactly why tools like Rails are getting so popular. We don't need or want to write this rote code over and over again.
I still think that if you don't expect O/R mapping to be a silver bullet which will absolve you of all your database pains--O/R mapping provides you with a good balance between benefits and costs.
Posted by Arnon Rotem-Gal-Oz at 12:12 AM Permalink
|
June 26, 2006
The Advanced Message Queue Protocol (AMQP)
The Transaction Workflow Innovation Standards Team (Twist) has just launched Version 0.8 of the Advanced Message Queue Protocol (AMQP), a proposed protocol for Messaging Middleware interoperability.
The main difference between AMQP and existing standard JMS is that JMS is an API standard, while AMQP is a binary standard. APIs such as the JMS API can be mapped to the AMQP commands which support very similar semantics. AMQP is an open standard and is the product of RedHat, JPMorgan, Iona, Cisco, and others.
AMQP is being drafted with performance and scalability in mind here is a short quote from the spec that demonstrates the scalability goals:
The scope of AMQP covers different levels of scale, roughly as follows:
- Developer/casual use: 1 server, 1 user, 10 message queues, 1 message per second.
- Production application: 2 servers, 10-100 users, 10-50 message queues, 10 messages per second (36K
messages/hour).
- Departmental mission critical application: 4 servers, 100-500 users, 50-100 message queues, 100 messages per second (360K/hour)
- Regional mission critical application: 16 servers, 500-2,000 users, 100-500 message queues and topics, 1000 messages per second(3.6M/hour)
- Global mission critical application: 64 servers, 2K-10K users, 500-1000 message queues and topics, 10,000 messages per second(36M/hour)
- Market data (trading): 200 servers, 5K users, 10K topics, 100K messages per second (360M/hour)
As well as volume, the latency of message transfer can be highly important. For instance, market data becomes worthless very rapidly. Implementations may differentiate themselves by providing differing Quality of Service or Manageability Capabilities whilst remaining fully compliant with this specification.
(AMQP Spec 0.8).
The de facto "standard" today is Websphere MQ which controls about 80% of the messaging market -- the aim of AMQP is to commoditize messaging services by presenting an open standard (and cheap) binary protocol.
Although the spec version is 0.8 I think the standard is still in initial stages as more work is needed on several areas; for example, security and WS interoperability (which isn't addressed in the spec itself and mentioned briefly on the site). Nevertheless, AMQP looks promising and I hope it gains momentum in the industry. Specifically I hope Microsoft joins this effort to ensure platform interoperability -- the same way they (Microsoft and Sun) have done for Web-Services.
Posted by Arnon Rotem-Gal-Oz at 06:45 AM Permalink
|
June 23, 2006
Interface Segregation Principle
Back to blogging about some object-oriented principles. This time I examine a simple principle--the Interface Segregation Principle (ISP).
ISP is a sort of the poor man's Single Responsibility Principle (SRP). While SRP addresses high cohesion in the class level, ISP is about high cohesion in the interface level. In other words, you create client (type) specific interfaces so that users will not have to depend on functionality they don't need.
ISP is a special case of a wider principle called "Separation of Concerns" in which each interface deals with a specific aspect of the behavior.
Here is a simple example for applying ISP: Consider a drawing program where you build a a rectangle class that has some logic (e.g. calculate area) as well as drawing logic (e.g. render itself on the screen using DirectX). If you also have some algorithms that also need the area calculation of the triangle, the algorithms are now dependent on DirectX. When applying SRP this would be refactored into two classes, while with ISP it would be refactored into two interfaces and the algorithm would only depend on mathematical oriented one. Robert C. Martin described ISP in detail in Interface Segregation Principle.
ISP can be used as a solution where a class violates SRP from some reason (to help protect the class users). Another common use of this principle is as a second step for increasing cohesion and separation of unrelated parts. Interestingly determining what client specific interfaces you should have can be done using similar principles mentioned in another post : Consumer Driven Contracts. There are several key differences though. Services granularity is very different from classes granularity and more important ISP promoted fine-grained interfaces while contracts promote coarse-grained ones.
Posted by Arnon Rotem-Gal-Oz at 08:47 AM Permalink
|
June 22, 2006
Architecture Dilemmas: O/R Mapping Why/When (Part III)
This is the last part of a three part series on O/R mapping. Part I provided some background on the subject. Part II described the benefits of O/R mapping and analyzed some of the costs of using O/R mapping. Part III (this post) provides my opinion and some guidance.
O/R mapping is not a panacea, as was shown in the previous post. Using O/R mapping incurs several costs (which are sometimes hidden at first glance). Nevertheless, using O/R mapping provides a good balance between the need to bridge the gap between an OO model and a relational one versus the time and effort needed to provide that bridge. O/R mapping is especially useful if you are also following Domain Driven Design principles which support a rich and meaningful (domain) object model.
Several years ago (good) O/R mappers were hard to find. The first real O/R mapper I used was TopLink (now Oracle Toplink)--indeed the Java world seems to be leading the adoption of O/R mapping into mainstream programming. Now there's Hibernate (which is rather popular), JDO (I think the first O/R mapping standard), and now the Java Persistence API as part of EJB 3.0.
On the .Net side there's a wide range of solutions, starting with NHibernate (the .Net version of Hibernate) and many commercial and open source solutions. Microsoft is following this trend and will be introducing two new O/R mapping frameworks: LinQ for SQL (formerly known as "DLinQ") and LinQ for Entities (built above ADO.NET entity framework).
When a solution has mostly with data-entry screens or simple CRUD operations, a viable option is to use the ActiveRecord pattern. ActiveRecord is basically a simplistic O/R mapping (actually it can be considered as an R/O mapping as it is the table row that is the mapped to an object). While ActiveRecord provides an anemic domain model it can still be useful in the scenario mentioned above. The added benefit of ActiveRecord mapping is that it is simple to generate this kind of mapping automatically (e.g. what Rails or MonoRail do).
DAL (Data Access Layer) or direct data access are a good options when the solution is very data centric and/or database intensive. A classic example for this would be a reporting application. iBAT is is a variant on the DAL theme (I consider it an XML-based DAL). The good news is that the SQL is externalized from the code and can be tweaked and updated independently. The downside include lacking documentation as a lot of mapping files (mapping per query/SQL statement).
Lastly, on smaller projects which are not very data intensive, you can also consider using an object-oriented database (such as Versant FastObjects, Objectivity, or db4O). While I wouldn't use them to create the next version of the NYSE data center, they can make life very easy where the data requirements are modest.
There are many ways to get to the data from the object model. Each approach has it place and sometimes it is worthwhile using more than one in a project. Whatever approach you take. I believe it is a good practice to consider utilizing the Hexagonal architecture principle and keep the objects clean from the data access code (POJO/POCO).
Posted by Arnon Rotem-Gal-Oz at 07:30 AM Permalink
|
June 19, 2006
Architecture Dilemmas: O/R Mapping Why/When (Part II)
In Part I of "Architecture Dilemmas: O/R Mapping Why/When" I briefly explained what Object/Relational (O/R) Mapping is as well as presented some of the other options available for getting data from a relational database (RDBMS). In Part II, I examine some of the motivations to use O/R mapping and some of the costs and limitations O/R mappers.
The premise of O/R mapping is that you have a focused investment in creating the mapping and that you are free from worrying about the data structure.
This leads to quite a few benefits for using O/R mapping:
- Clean OO design. Hiding the relational model specifics lets the object model be more cleanly analyzed and applied.
- Productivity. Simpler code as the object model is free from persistence constraints. Developers can navigate object hierarchies, etc.
- Separation of concerns and specialization. Let the DB people worry about DB structure and the Object people worry about their OO models.
- Time savings. The O/R mapping layer saves you from writing the code to persist and retrieve objects. O/R mapping tool vendors claim 20-30% reduction in the code that needs to be written. Writing less code also means less testing.
One problem with O/R mappers is that they usually commit the "Needless Repetition" deadly sin (a.k.a. DRY–-"Don't Repeat Yourself"). The table structure as well as their relations are stored both in the DB and in the mapping files used by the O/R mapper. This causes a maintenance problem as you need to ensure that both versions of the meta-data don't get out of sync. Rails (as in Ruby on Rails) partly solves this problem by relying on naming conventions. (Note: You can also override the default mapping.) In other environments, you can use code generation for the mapping file to get a similar effect. Both of these approaches result in limited mapping--which means you are likely to switch to manual mapping so you can benefit from the DB capabilities.
Which brings us to another problem with O/R mappers. Writing these mapping files is a daunting task (unless we are talking about trivial mappings) not to mention that O/R mappers tend to have favorite mappings (e.g., class = table or class hierarchy = table etc.) and trying other mapping are more complicated (if at all possible). This needs to be updated every time you change the DB.
One approach I've been taking recently is to isolate the DB structure from the DB side as well; that is, to add database views that expose the DB to the O/R mapper in simple-to-map structure. which means the mapping is simple and straightforward and the database is free to evolve and adapt as needed. For example, in one project we have set up "self-recording" where each update on the view resulting in an insert on the underlying table(s), while the view always reflects the latest version. Other views or queries can be used to go back in time to an earlier snapshot of the data. The downside of this approach is, of course, the double mapping layer (but at least O/R mapping is simple and relatively stable) hasn't been tested for high-data access load scenarios (as with the projects where it is used don't have such characteristics )
Then there are the queries, which is where a lot of O/R mappers stumble. You either get limited query capabilities or you get performance problems on complicated queries which means that you may need to resort to writing the queries manually (if your O/R mapper supports this)--which is what you were trying to avoid in the first place, not to mention that if your team is already familiar with DB techniques (SQL etc.) There's also the added overhead of learning that new query language. If you do feel comfortable with SQL and you want to take the middle ground you can use iBATis which lets you externalize the SQL into XML.
Note that you probably want to look at O/R mappers that support features like caches, lazy initialization , batch modes etc. to help avid the performance problems mentioned above.
On the next and final post on O/R Mapping I'll recommend when and when not to use O/R mapping.
Posted by Arnon Rotem-Gal-Oz at 06:32 PM Permalink
|
June 16, 2006
The Architect's Role: A Holistic View
Following the series of posts that discussed whether architects should code (see Part I, Part II and Part III), I thought I'd expand on how I see the software architect's role.
To be a good architect, a person needs to have experience taking a project from inception to production and maintenance, they should have project management experience, and have spent time working directly with customers. On top of that, know-how and experience is needed in design and technology. Having a diverse experience is what enables the architect to have a wide view on a project, understand the need for pragmatism, better understand stakeholders concerns as well understand the implications of design and technology decisions (on scheduling and budgeting, for instance). Having a wide experience also puts architects in a unique position where they can really help make projects meet their goals.
Software Architecture deals with the system's quality attributes. This makes the architect the ultimate person responsible for making sure the solution meets these quality goals (and I don't mean quality as in low bug count, rather the soundness of the solution and it ability to address the various stakeholders concerns).
To make this quality claim a reality I tend to take a holistic view in regard to the architect's role, which, simply put, means that the architect needs to do whatever it is needed to make the project go forward and succeed. Taking this direction toward quality is only possible if the architect has the wide range of experiences mentioned above.
How does that translate to real life? Here are few examples for "non-architect tasks" from my experience:
- On one project the system engineering team was working in the wrong direction in regard to analyzing requirements (this cost us six months of delay). I helped introduce the concept of Use Cases and created the project's initial use case model. (You can read the insights I have from my experience in my paper Use Case Methodology for large systems (pdf) )
- On another occasion one of the project managers was trying to evaluate how a certain technology will help advance the project. I helped her construct the WBS of the activities needed to complete the needed functionality (assuming the technology is in place) and the helped her create the estimates.
- On another project we had performance bottlenecks related to the technology used (ESRI, displaying vector maps with high refresh rates for displayed objects). I got together with another architect to pin-point the problem, diagnose it, and came up with a solutions (mapping ESRI temp files to a RAM-disk).
- I worked on a project where time was running out and a milestone was looming fast. I helped introduce the project to some SCRUM-like techniques (why only "SCRUM-like"? Remember that Rome was not built in one day either) and by working closely with the PM helped the team reach the milestone successfully (indeed not all the feature were completed--but the ones that did work were the features important to the end-user which made the milestone a success).
And the list goes on and on. And yes, coding can also be a part of this list (though for me it usually only translates to writing short proof of concepts--and for others it may mean coding some of the tasks with the team).
To sum up, a good architect is not just a lead developer on steroids. An architect should have a much wider range of capabilities and experience. Architects are "enablers". They should use their capabilities to help advance the solution and ensure its overall quality.
Posted by Arnon Rotem-Gal-Oz at 04:56 AM Permalink
|
June 14, 2006
Architecture Dilemmas: O/R Mapping Why/When (Part I)
In this first blog on "Architectural Dilemmas," I am going to examine object/relational (O/R) mapping. In Part I, I'll provide some background on the subject; in Part II, I'll present some of my opinions on the topic.
IT systems need persistent storage (unless, of course, the systems are really trivial ). This persistent storage usually comes in the form of a relational database, such as Oracle, Microsoft SQL Server, IBM UDB, and the like. There are several alternatives to RDBMSs; for instance, object-oriented databases (OODBs) db4o, persistent object stores (Prevayler, XML databases, and the like.) However, at least until now these alternatives haven't really caught (maybe I'll discuss why on another post) and the fact is that RDBMSs remain pretty much ubiquitous.
Thus you are faced with the task of getting data from the DB into your business logic. Unfortunately the object model and the relational model are somewhat at odds (what Scott Ambler calls "Impedance Mismatch") which means that a properly designed object model will not have a direct automatic map between objects and tables.
The result of that mismatch means that you need to get the data by using one of the following approaches:
- Direct data access; not highly recommended. Retrieve/Save by using SQL calls(either dynamic SQL or a stored procedure) whenever needed by the business logic. The reason this is not recommended is that there is no separation between.
- ata Access Layer (DAL). Have an object (per table) that knows how the tables are constructed. The DAL objects retrieves the data. Sometimes this is combined with Data Transfer Objects (objects with only setters/getters to change the data) to transport data between tiers.
- ActiveRecord. A class that has the same structure of a table fields. A class instance represents a row in the table and static methods affect the whole table. The class abstracts the SQL needed to actually get to the DB.
- O/R Mapping. Have a layer that is responsible to bridge the gap between the "proper" object model and the "proper" database model.
There are several variants for each approach and mixes of the approaches; for example, the ActiveRecord implementation in the castle project which builds on Nhibernate, an O/R mapper.
Many implementations (for the various methods) use code generation (there are hundreds of generators you can find many of them ordered by platform at http://www.codegeneration.net). There are implementations that use stored proecdures and there are ones that rely on dynamic SQL. Plus there are few middle-ground approaches like iBatis.
In Part II I will discuss motivations to use O/R mapping (over the other approaches) as well as when not to use O/R mapping.
Want to have your dilemma analyzed? Send your architectural/design dilemmas to ask@rgoarchitects.com.
Posted by Arnon Rotem-Gal-Oz at 02:18 AM Permalink
|
June 13, 2006
Consumer Driven Contracts
Ian Robinson, a developer at Thoughtworks, has published a very good article called "Consumer-Driven Contracts: A Service Evolution Pattern".
In the paper, Ian examines the different approaches to contracts--provider contracts, consumer contracts or consumer-driven contracts. (I briefly voiced a similar approach for the initial contract design.)
I highly recommend taking a look at Ian's article. By the way, I think the same mindset should be kept even for designing object interfaces.
Posted by Arnon Rotem-Gal-Oz at 04:48 AM Permalink
|
June 09, 2006
Who Put the S in SOA?
The problem with TLAs ("Three Letter Acronyms") is only second the problem caused by the CI's ("Computer Industry's") tendency to overload terms.
On the SRP post, one reader commented that the term "Responsibility" is problematic, because it overloads the "responsibilities" used in CRC-based analysis (see the comment for more details and my response)
Overloaded terminology adds to the confusion around SOA ("Service-Oriented Architecture"). For one there are "windows services" (thankfully in Unix/Linux we call them "daemons" so we're better off). Another overload, shared by many people, is that service is just a term for a software function (for example, SQL Server Notification Services, or "log service", "persistence service" and so on). This assumption, by the way, helps propagate the misconception that "web services" = SOA. I've seen it happen many times that people think that if they slap a web-service API on an application they are on the way to SOA nirvana. Well, that is just plain wrong. What Web services does is to allow exposing methods for remote consumption over HTTP. This can be used to create bona fide SOAs but also to create good (?)-old RPC style systems.
So, what are the Services in SOA?
The services in SOA are business functions--Accounts Receivables, Shipping, and so on. Thus, SOA means architectures that enable alignment of software components/agents to business functions. A service needs to be a cohesive (appropos SRP) bundle of objects, excecutables, and that likec that cover and encapsulate a sepecific business area.
Again, I'll further develop it when I'll explain why I think SOA is an architecture style.
Posted by Arnon Rotem-Gal-Oz at 06:04 AM Permalink
|
June 07, 2006
DI and TDD: The Dynamic Duo
[Edited 08/15 - fixed broken link (thanks to Julia Renouard)]
I am probably overstating the obvious here, but one of the valuable side effects of practicing test-driven developement (TDD) is that it encourages the use of dependency injection (or is it the other way around?).
What's dependency injection (DI)? In a nutshell, DI means that a class does not instantiates any other classes. Instead, it depends on the classes that are "somehow" injected into it.
This is probably best explained with an example. (While this code is in C#, it is generally generic):
public class Controller
{
IView view;
//old way
public Controller()
{
this.view = new View();
}
//new way - Using Inejection
public Controller(IView tView)
{
this.view = tView;
}
}
(You can read a more thorough explanation of this at Martin Fowler's site.)
The Controller in this example needs a view to operate. Using DI, the view is expected to be instantiated by someone else and the controller will get the view instance when the controller is instantiated. Another option is to use a setter method (the dependency is injected after the class is instantiated). Lastly there's getter injection--but that requires using aspects to weave the dependency into the class.
Why do you need DI? For one thing, it helps introduce loose coupling--using DI, the Controller class above is only dependent on the IView interface and not on the view implementation. Using DI also means we can supply different views (provided they adhere to the IView interface) and the controller won't have to change.
Note that when you use DI, the injected class loosens control on the lifetime of the dependency (in the example above, the Controller no longer instantiate the view). If you need the object lifetime control you can inject an abstract factory instead of injecting the target class.
Furthermore DI makes classes more testable (which is why DI works so well with TDD). In the "old" example above, it is hard to have the Controller as the unit under test since we also need the view. If we use DI, the test fixture (or test method) can give the unit under test (the Controller in the example) a Test Double (dummy, fake, stub or mock) so that the unit under test can be as small as you like.
If you want to use DI, you don't have to build the infrastructure (factories, assemblers, etc.) to support DI by yourself. There are several frameworks that do this for you: spring and spring.net are the most famous, but there are few others like picocontainers, objectbuilder, and so on.
When practicing TDD, you find yourself more and more inclined to used DI as it will makes your tests smaller and easier to write. As mentioned above, when you use DI you also improve the overall design of the class. It is more portable, interface-based programming makes the classes less fragile, and so on, thus as this blog's title says
DI and TDD really are the dynamic duo--with one helping promote the other and vice versa.
Posted by Arnon Rotem-Gal-Oz at 07:30 AM Permalink
|
June 05, 2006
The Single Responsibility Principle
In a previous post I discussed how the Open Close Principle (OCP) is one of the most basic principles of OO design. This post is focuses on the Single Responsibility Principle (SRP), also known as "high cohesion" which is another fundamental design principles.
The Encarta Dictionary defines cohesion as:
Sticking or working together: the state or condition of joining or working together to form a united whole, or the tendency to do this.
The same should be true for classes. A class should be cohesive; that is, have only a single purpose to live and all its methods should work together to help achieve this goal. Or in Robert C. Martin's words:
There should never be more than on reasons for a class to change.
When a class has more than one responsibility (that is, reason to change) these responsibilities are coupled. This makes the class more difficult to understand, more difficult to change, and more difficult to reuse (rigidity, immobility and needless complexity). Cohesion should also be applied at the method level--and for the exact same reasons.
You can also take a look at David Chelimsky's blog where he talks about not fragmenting that single responsibility between classes.
The challenge with SRP (and with David's extension of it) is getting the granularity of a responsibility right. For example, if I have a class that represents a business entity, should it also save itself to the database? Is handling all aspects of the customer including its persistency a single responsibility or is handling its business aspects one and persisting the second? In "Patterns of Enterprise Application Architecture" Martin Fowler et al. present the "ActiveRecord" pattern where a class wraps a database row (the first option described above). On the other hand, Alistair Cockburrn describes the Hexagonal architecture which talks about separating domain from transformation--persisting to a database (the second approach described above). I'll discuss additional aspects of this particular issue shortly when I examine architectural dilemmas.
Sometimes it is easier to see the responsibilities are unrelated. For instance, consider the same customer entity mentioned above. Should it also contain the logic needed to render it on the GUI? Here it is easier to see that the GUI representation should be handled in a different class. GUIs change a lot (relatively), and the entity may have several views on the UI (a grid, a specific form etc.). The entity and its representation may need to run on completely different tiers etc.
Sometimes the second responsibility may seem so trivial you may be tempted to leave it anyway. For example, creating a (threadsafe(!)) singleton in C# (if you don't want lazy initialization) is as simple as:
sealed class Singleton
{
private Singleton() {}
public static readonly Singleton Instance = new Singleton();
// other business related code goes here
}
Why bother separating the responsibility to have a single instance (singleton) from the business responsibility?
The reason is the coupling this induces on the consumers of the class which is very hard to remove. I recently had to do just that. I worked with a group that had a few singletons and code with dependencies on them. It was basically some application-level protocol layer (for communicating with external devices) the idea was to reuse it for a sister project that had to talk with the same devices. They said they had some problems reusing the code and asked me to take a look to see if I can help. I thought that since we're talking about the same devices, plus some of the code is generated it would be a breeze, maybe we'll do some refactoring and everything will be okay. It turned out we had to do a major redesign to uproot all the application specific singletons in to make the core code more mobile. You can read more on why singletons are bad on the C2.com Wiki and on Scott Densmore's blog.
One last point regarding SRP: If you cannot separate the responsibilities into separate classes, at least consider separating them to different interfaces. I will elaborate on this when I'll write on the Interface Segregation Principle.
Posted by Arnon Rotem-Gal-Oz at 04:58 AM Permalink
|
June 01, 2006
Architecture Styles
Architectural style defines a family of solutions in terms of a pattern of structural organization using a vocabulary made of specific components and connector types and the constraints on their use.
Several styles can be composed to create compound or derived styles (see for example this link which demonstrate how the REST style is derived from other styles).
The definition of architecture style is derived from the definition for software architecture.
Software architecture is the collection of the fundamental decisions about a software product/solution designed to meet the project's quality attribute requirements. The architecture includes the main components, their main attributes and their collaboration (i.e. interactions and behavior) to meet the quality attributes. Architecture can and usually should be expressed in several levels of abstraction (depending on the project's size). If an architecture is to be intentional (rather than accidental)--it should be communicated. Architecture is communicated from multiple viewpoints to cater the needs of the different stakeholders.
(See my post on "What Is Software Architecture".)
The family of related architectures just mentioned is created when you define some of the elements and add constraints on their interactions or as SEI's architecture glossary defines Architecture style:
A specialization of element and relation types, together with a set of constraints on how they can be used.
For example, consider the "Layered architecture" style which is composed of layers (the components) which provides facilities and has a specific roles. The layers have communication paths/dependencies (the connectors).
In a layered style, a layer has some limitations on how it can communicate with other layers (the constraints). Typically a layer is allowed to call only the layer below it and be called only by the layer above it. (That said, there are variants; e.g., a layer can call to any layer below it; vertical layers that can call multiple layers; etc.--as long as the layers communication paths are limited by some rules)
The layered architecture style is very popular to the point of almost being ubiquitous: logical software layers (e.g., presentation component, UI Controllers, business processes, business components, data entities, data access layer), SOA layers (fundamental, Intermediate, Process), physical tiers (e.g., database server, application server, web server and clients) etc.
There are many other architecture styles, including for example pipe and filter, push based, peer-to-peer, blackboard, MVC, PAC, or the more recent Adaptive Object Models, REST (mentioned above) and...SOA (though some will probably disagree ). On my next post I'll explain why I think SOA is an architecture style.
Posted by Arnon Rotem-Gal-Oz at 01:14 AM Permalink
|
|