Tag Archives: architecture

Blueprints

Evaluating a Proposed Application Architecture

At work, I’ve recently had a few conversations about the best way to evaluate candidate architectures for a software project, so I decided to put down a few ideas I have on the topic.

Project Intake

Firstly, there are several questions that need to be answered and understood by all stakeholders of a project before you can properly evaluate an architecture:

  • What are you planning to build?
  • Why are you building it?
  • Who are you building it for (i.e. who is your audience)?
  • How will success be measured?

At a technical level, most projects start with an answer to the first question and have a weak or vague understanding of the other three. However, if you can’t answer those three questions, you don’t have a good justification for the answer to the first one.

The first task is to get agreement on the answers to Questions 2 through 4 and verify the answer to Question 1 still fits. If it doesn’t, use the opportunity to identify what can be built that fits the needs of the answers to Questions 2, 3, and 4.

Business Environment Analysis

Most technical ecosystems have processes and expected technical standards that apply to all applications within the ecosystem. Your organization does things a certain way.  Your team likely has expertise in a specific technology.  Your business also likely has requirements around protecting the environment and facilitating support of the application.  These factors should be identified:

  • How are applications expected to authenticate and authorize users?
  • Are there standards around data security?
  • Are there standards around data retention?
  • Are there standards around transport protocols?
  • Are there expectations around supported platforms?
  • Are there standards around accessibility?
  • Are there standards around logging?
  • Are there standards around analytics?
  • Are there expectations or standards around interoperability across applications?
  • Are there standards regarding UI conventions?
  • Will the new product provide technical challenges to existing distribution and delivery models?
  • Will the new product provide technical challenges to existing support mechanisms?
  • Are there standards around code documentation?
  • Will the new product provide technical challenges to existing documentation procedures?

The answers to these questions will identify many of the inherent technical requirements of the system. These aspects are related to the notion of certifying the application as “good and complete” as your organization defines that term, even if informally.  If there is no formal certification process, either within your company or externally, for the application, answering these questions will help define what “good and complete” means to your product.

Technical Environment Analysis

The next step is to identify what you already have in place and how the new product will fit into the overall ecosystem.  Few applications are 100% greenfield with zero dependency on existing systems, so it is paramount to understand what environment you will be working with.

  • What systems are already in place?
  • What role will those existing systems play in the new product?
  • How will the new system affect seemingly unrelated products?
  • What types of access privileges are required to interact with these systems?
  • What integration facilities already exist in the identified systems?
  • What data does the new application need and where can it pull that data from?
  • In what formats are the data accessible?
  • What second-level dependencies exist?

Technical Architecture Review

At this point, we should have enough information to apply a proper architecture review. Firstly, you verify the proposed architecture addresses all of the concerns identified in the Business and Technical Environment analyses.

After those business-related concerns are addressed, most of the remaining aspects of the architecture will be technically focused.  However, technical concerns tend to be highly domain and context specific.  The meaning of “good and complete” when it comes to these technical concerns will be influenced by the programming language, platform, organization, and product. In general though, the following concerns tend to apply regardless of context and can be used as a base set of technical concerns to review regardless of project:

  • Separation of Concerns: Each component of the system should only do one thing and do it well. In practice, this minimally means ensuring a strong separation between the business logic implementation and the UI.
  • Abstract Interfaces: Are the touch points between the system integration points and product components done in a way that effectively hides implementation details of both sides of the integration?
  • Scalability: Can the proposed implementation easily scale to accommodate concurrent execution of the same logic processes across different data sets?
  • Maintainability: Is the architecture well reasoned, consistent, and easily modified?

When Should Architecture Reviews Occur?

You do not want an architectural review to impede the development process. Your goal is not to create the “perfect” architecture.  Your goal is to build a solid product.  However, you want to identify issues with a proposed architecture early enough to do something about any problems an architecture may have.

  • Ideally, a review of a proposed product architecture should occur before any coding has begun. (This is nearly impossible to achieve in my experience.)
  • A more realistic ideal is that a full architecture review should be conducted as soon as a potential product’s prototype or alpha implementation is minimally functional.
  • At a minimum, a full architecture review must be conducted as soon as a proposed product reaches the release candidate stage if one has not been completed earlier.
  • A full review should be conducted once prior to the product’s initial release. As soon as this occurs, summary reviews of the architecture will likely be sufficient at subsequent steps of development and maintenance.
  • For ongoing development, a summary architecture review should occur at the start of each new release and again as part of the project’s release criteria (ideally at the end of the last development sprint) or as soon as the first release candidate is identified.

A Reality of New Product Development

Most new products/applications start out as skunkworks projects. Typically an individual or a small group builds a product prototype and uses that prototype to gain approval/funding for the project.  As a consequence,  a new product often starts life with a sizable, un-vetted code base and significant technical debt. The process for bringing these products to production involves:

  • Conducting a full architecture review.
  • Documenting gaps in all of the aspects identified above.
  • Conducting a full code review.
  • Identifying all technical debt as issues/defects in your project tracking system.
  • Prioritizing architectural gaps and identifying gating issues.
  • Creating a plan to address all non-gating issues in a timely manner.
  • Verifying that all gating issues are addressed before the product is released to production.

The process I’ve laid out is intentionally light on specific procedural details because each organization is different and each technology stack and platform carry specific technical concerns.  The mechanics of a formal architecture review process need to be crafted based on the specific needs of your organization and the technology you are using.

However, this outline should provide a good abstract notion of what goes into an architecture review.  The items and concerns I’ve outlined probably aren’t comprehensive.  If you feel I’ve overlooked something important, please mention it in the comments.

Markers

Marker Interfaces

Marker interfaces tend to be one of those things that your don’t think about often.  But when you have a problem they can help you solve, you think they are awesome.  The trick is knowing when they should and should not be used.

What is a Marker Interface?

Marker interfaces are basically an interface contract with no methods or properties specified.  The notion of interface contracts are common in many languages but take on many different names.  If you’re familiar with Java interfaces, Objective-C protocols, C++ pure abstract classes, or any similar technique in your language of choice, you know what I’m referring to.

Typically, an interface contract specifies a set of methods that must be implemented by any object that intends to support the contract.  This enables you to refer to an object by the contract (which typically corresponds to a functional role or feature role in the program) rather than the concrete type of the object itself.  This both clarifies how code consuming an object intends to use the object and makes it possible to easily use different concrete classes that also implement the contract without needing to change the consuming code.  The consumer doesn’t care about the concrete object type as long as it satisfies the contract.

So why on Earth would you ever want to create a contract that doesn’t specify any methods?  Most of the time, you don’t. But if you need a way to abstractly specify an object type, especially when the abstract type may have concrete instances that don’t share a meaningful inheritance chain, then marker interfaces are likely a perfect solution.  You most often have a need to specify an abstract object type like this when you have orchestration or coordination code that is transferring objects from one part of a program to another.  The orchestration code doesn’t need to use or modify the object, it just needs to move it from one place to another.

Such orchestration code tends to be both fairly abstract and highly leveraged within an application’s architecture, so you often don’t want to specify concrete types for the objects being sent back and forth.  A simple way of generically passing objects is to specify the parameters of methods in the orchestration code as generic objects.  But specifying transfer method parameters as a generic object has a few downsides.  Firstly, it doesn’t provide any guidance to the caller about what should be passed.  Secondly, literally anything can be passed.  If you accidentally pass an object you didn’t intend to, the compiler/parser won’t catch the error.

void transfer(Object data)

Marker interfaces help avoid these problems.

By using a marker interface, you can specify the intent of what should be provided to the method without restricting you to a specific type or inheritance chain.

void transfer(IFooDataObject data)

This method signature is much clearer to the person using the method what type (in the functional intent sense of the word) of object should be passed to the method.  Any concrete type can still be passed, but you have to make a conscious choice about which objects should be allowed to be passed by adding the marker interface to the type definition of the object before you can pass an object of that type. In a mature architecture, prior decisions about which objects carry this declaration can greatly minimize confusion about what to send where.

You also get a level of type checking via the compiler, so if you accidentally pass a reference to a UI control object instead of the data property on the control you intended to pass, the compiler can let you know.  Without the marker, it wouldn’t.

This technique of using marker interfaces for high-level type specification is really the one application of marker interfaces I use frequently.  I tend to not like using marker interfaces to direct flow of control within an application (i.e. “if foo implements bar then do x”) because I think such control flow is typically better governed by object state than by type. But that thought is probably worth a post of it’s own.