Featured post

Object-Relational Mapper - Do we need this?

This article is based on a discussion with Raphael Parree . Many thanks to him. What is an ORM? An ORM is a framework that helps to map...

2017-10-15

JBoss EAP 7 Dev Training (Oct 2017) - Trainer's statements and guidelines

Last week I participated to a training about JBoss EAP 7 development.
These are the trainer's statements and guidelines - as I recall and understood them, and completely out of context.

Web applications

  • Always front the JavaEE container with a fronting HTTPS web server (for example Undertow or the Apache httpd server) which should host all static files and act as a reverse proxy forwarding requests to dynamic resources to the JavaEE container.
  • Do not set up SSL on the JavaEE container. Set it up on the fronting web server.
  • Go for a JavaScript framework.
    • JavaScript VMs/engines are nowadays incredibly fast.
    • The whole world is already there.
  • Coming from a Java developer experience, use TypeScript instead of JavaScript.
  • My conclusion: With JSF, use BeanValidation (JSR 303) instead of JSF validators.
    • JSF validators depend on the component, while data validation has nothing to do with the page structure/component hierarchy.  There is no reason to couple validation of incoming data with JSF page's components.
  • There is no reason to submit to the server data that has not been validated before by JavaScript in the browser.
    • This is not how JSF works. This is a reason why we should avoid using JSF.
    • Addition by myself: Validation by JavaScript does not mean that the server can trust the incoming data.  The server should always validate incoming data.
  • JSF will eventually die, the question is when.
    • During the next 5 years?
  • Use ReactJS
    • It is backed and actively used by Facebook
    • AngularJS is backed by Google, but it is not really actively used by Google.

Web services & integration

  • Use REST
  • Use JSON Web Tokens for request authentication
  • Use Protocol Buffers for REST (instead of JSON) & JMS
  • Avoid distributed transactions, rather use compensation instead, as in real life.
    • The concept of transaction mandates that everything inside the transaction happens at the very same instant, while it is actually not the case.
  • With REST services, use a HTTP POST if you don't know the ID of the generated resource.
  • Use Spring REST instead of JAX-RS and RestEasy.
  • Test REST services using httpie.org
  • JAX-RS creates, by default, 1 resource class instance per request.
    • This does not scale (instantiation of objects is slow, and GC time increases, which consumes too much resources).
    • Instead, implement the @Override getSingletons() operation
  • With JAX-RS, do not use class attributes to get request headers, cookie data etc. This would imply that the one-request-per-instance strategy is needed, which does not scale well.
  • Use Jackson to do JSON binding
  • With JAX-RS, prefer to return Response objects.
  • Use Akka-HTTP to implement REST services.
    • There are both a Scala and a Java API.
    • This is a non-blocking API, which thus scales well (threads are not blocked waiting).
    • This REST API has a client-side API as well
  • For security of REST services, using BASIC auth + SSL (+ JSON web tokens) is OK
    • Both Spring REST and Akka HTTP support this out of the box.
  • MOM (message oriented middleware) is the de-facto standard for inter-system communication in large organisations.
  • You should not use a big single ESB anymore
  • Use asynchronous JMS clients
  • Use Apache Camel

CDI & EJB

  • Avoid using @Producer
    • Use producers when you need to create instances of classes of libraries/frameworks which come with their own factories: the @Producer method would thus just be a facade for these specific factories
    • Your own beans are automatically instantiated by the CDI container anyway, provided they are marked with a bean-identifying annotation.
  • Do not produce primitive (int, boolean...) or String values with @Producer, rather set the values as static variables or access these values using static methods
  • Use EJBs. There is no reason to avoid EJBs in favour of CDI-only solutions (for transactionality and security, like provided by Apache DeltaSpike).
  • Apache DeltaSpike is not mainstream, and is not supported. Be cautious about using it.
  • Inject required attributes and objects directly into the constructor, instead of using setters or attribute access.
    • If a required attribute is not available, construction should fail and the object should not be usable anyway
  • There is no need to put an interface on stateless session beans or Spring beans. Stateless session beans and Spring beans needed interfaces in the past because the generation of proxies without interface was not possible. Nowadays, with javassist and cglib, this is no more the case. The architectural benefit of putting an interface on a stateless session bean or a Spring bean has never really been used anyway.
  • You mostly want to use @Singleton beans.
    • By default, access to any method of a singleton bean is write-locked.  There is one write lock per bean instance. As there is only one singleton bean instance, there is one single write lock for all method calls, which means that methods are called sequentially, one at a time, which has a dramatic impact on performance.
    • Use @Singleton with @Lock(LockType.READ) for better performance.
  • In Session Beans, any system exception is wrapped by an EJBException by the container.
  • The EJB scheduling is quite poor compared to other scheduling APIs or frameworks.  Prefer using Quartz instead of EJB scheduling.
    • Quartz is anyway the de-facto standard in Java programming world.

Load-balancing, clustering & multiple JavaEE container instances

  • To store shared transient (non persistent, like session attributes) state, use the client's browser storage instead of distributed replicated session mechanisms.
  • Use load-balancing and stateless services
    • Avoid stateful EJBs

Wildfly & JBoss EAP

  • Put custom modules directly into the module folder of the Wildfly distribution, as siblings of the module/system folder.  Do never modify anything inside the modules/system folder.
  • A JBoss modules slot specifies a version of a module.
  • Do never work or modify with the original standalone or domain folder of your JBoss EAP/Wildfly distribution. Always use a copy.
  • Deploy DB drivers as JBoss modules, then register the driver into the container by referencing the corresponding module, then define your datasources using the registered driver.

IDE

  • Use Jetbrain's IntelliJ IDEA Ultimate edition.
  • Forget Eclipse.
  • During development, always deploy exploded archives.
    • And in IntelliJ, enable JavaScript debugging.
      • This requires the installation of a Google Chrome plugin.

Testing

  • Unit tests do not relate to a method or to a class, but to a component. A component may be composed of multiple encapsulated classes.
    • The unit of test is the component.
    • What is tested is the behaviour of the component, not its internals.
    • If we test the internals of a component, like for example each class, we would end up with too many mocks and too many tests to maintain, while these would be easy to break (any implementation refactoring would imply to maintain the tests and mocks).
  • We should test our components.
  • Dependencies to other components (usually at most a few per component to test) should be mocked.
  • Read Martin Fowler's Is TDD dead article
  • Test-first is not TDD.
  • Test-first is nice in theory.  But it fails in practice. Do not apply it.
  • Use gatling.io for performance tests
  • Use Selenium +Arquillian Drone
  • Do component unit test + end-to-end tests.
    • If you cannot do end-to-end tests, then only you should do integration tests.
  • Read the testing book with a tulip on the cover
  • The trainer mentioned BDD and cucumber.io
  • Use the specs2 Scala library to implement tests

Development practices

  • Use Docker from DEV to PROD.
    • The whole world is going down that road.
  • Always favour strong typing instead of using String.
  • Read Eric Evan's Domain Driven Design book to understand what a domain model really is.
  • Do not use magic numbers (error codes or HTTP status codes, for example)
  • Use Scala instead of Java
    • Smoothly introduce Scala by first using it for unit tests, then for actual production code.
  • Use SQL. It is a decent DSL (domain specific language) for relational data access that has lived and not been replaced for decades.
  • Understand:
  • Do not used shared mutable state. It has to be managed (threads), and at a point there are just too many threads to manage: this thread management will eventually outweigh the advantage of adding a new thread.  This solution does not scale.
    • Use functional programming paradigms instead.
      • Functional programming has no side-effects, and uses immutable non-shared states. 
  • Go to functional programming: learn Scala if you come from Java development (Haskell for hard-core functional programming) 
  • Use the Functional Java library.
  • Checked exceptions are bad
    • Throwing an exception is like a GOTO to somewhere down the stack.
    • Put exceptional results into return values instead.
      • Use Optional<> or Either<> return values.
      • Don't throw the exception, put it into the return value.
    • System/unchecked exceptions (RuntimeException) is OK, they indicate that an error occurred and the system cannot continue.
  • NULL is bad
    • Cf. Tony Hoare's billion dollar mistake 
    • Use Optional<>/Maybe<> or Either<> instead.
    • Stop returning null.
    • Stop accepting null from an operation. Wrap results of operations that return null into Optional<>/Maybe<>.
    • In Java, Object is the Ur-/top-type: all classes extend Object, and similarly, null is a bottom-type: it inherits from all classes.
      • But its behaviour does not inherit from these classes: the JVM behaves as if the implementation of any operation called on a null instance throws NullPointerException. Operations that return a object may return null, in which case what you receive is not really an instance of the promised class - it is, but it does not behave like one. This is a major flaw in the design of the Java language, which is thus not quite "honest" about how an operation can behave.
  • Avoid distributed transactions.
    • They imply additional latency
    • They do not scale well.
    • For info: The XA protocol is one implementation of the two-phase commit protocol.
  • Do not force your service consumers to manage your versions.
    • Your server should manage as much as possible different versions without impacting the consumers.
    • Do not put version numbers in your URIs.
    • In case of incompatible changes and a consumer sends a deprecated request format, just return an error message/exception.
    • In the real world, there are no versions: imagine that you fill in a form for some administration.  If you provided an older version of the form that is not supported anymore, the administration will tell you to fill the newest version of the form.  Implement a similar behaviour in your services.
  • Use reactive streams (Akka streams, for example)
  • Use random generated identifiers
    • Like, for example, a UUID.

Persistence

  • Do not use JPA if performance is important.
  • Do not use JPA if you use an anemic domain model (and transaction script services).
  • JPA is an ORM, but we don't really use object orientation (and the powerful encapsulation that comes with it), thus there is no need for an ORM and all its complex magic. I wrote an article about it, with more details.
  • In Luxembourg, Clearstream and BGL use MyBatis.
  • JPMorgan switched from Hibernate to Mybatis.
  • Use Spring JDBC or MyBatis or ScalaJDBC, but not ORMs.
  • Do not use triggers or stored procedures. Remove all the ones you have.

Optimistic locking

There are usually 3 ways to implement optimistic locking:
  1. UPDATE... WHERE {all attributes have the previous value}
    1. If any fails, then it means that the object has been updated already
  2. UPDATE... WHERE {all changed attributes have the previous value} 
    1. If any fails, then it means that the object has been updated already - more efficient, but does this really work? Other fields may have been updated as well, and this strategy would not detect it.
  3.  UPDATE... WHERE VERSION=previous version
There is usually no reason to use a VERSION field, and it should be avoided.  This puts the burden on the developers to always check the value of the VERSION field, even if in some use-cases this is irrelevant.

DevOps

  • DevOps of a system is done by a single team, which is responsible for both DEV and PROD, as well as for the build and deployment.

Software architecture

  • Software architects work for the company, not for the project. In fact, many projects are define because of the architects, not because of the business.
  • Architectural policies apply between components
    • They define how components are integrated into a bigger system
  • Design policies apply to the internals of a component
    • They depend on the actual use cases and requirements for the component.
  • Evolution:
    • 20 years ago: Component Based Design (CBD)
    • 10 years ago: SOA
    • Now: microservice architecture (MSA)
      • At most one port (as in UML) per component
  • Read the book Microservices Architecture

Miscellaneous

2017-10-14

Object-Relational Mapper - Do we need this?

This article is based on a discussion with Raphael Parree. Many thanks to him.

What is an ORM?

An ORM is a framework that helps to map objects (as in object-oriented programming) into persistent relational data structures (tables in a relational database).
The Hibernate framework is an ORM framework.

Is there a use-case for ORMs?

In object oriented programming, encapsulation is key.  It hides the internals of objects, which only expose their interface.  Domain objects (these objects which represent things of the real world) are accessed using their interface, whose operations may change the internal state of the object.  In pure object oriented design, such internals are an implementation detail hidden from the object's client. The client just does not know how the object has changed internally, it just has the guarantee (provided there is no bug), that the requested change has been applied: the requested state transition of the object has been executed and the object is now in the requested state.
If this object needs to be persisted, an very widely adopted practice is to persist the object's state into a relational database.  This permits to ensure that the object is not lost (durability) as well as to remove the object from working volatile memory and thus reuse the freed memory for other purposes.
At a later stage, some process may need to access the object again.  As the state of the object has been persisted, we need to rebuild the object using this persisted state data.
We derive from the previous paragraphs the use-cases related to data persistence:
  • One needs to persistently store an object's state, possibly into a relational database.
  • One needs to retrieve this persisted state, possibly from a relational database, in order to re-build the object, with the same state.
NOTE: these are not use cases for ORMs.

About the state of an object

An object has behaviour and state.  The behaviour of an object is defined by operations that perform state transitions of the object.
What defines the state of an object? Its attributes. The object features a set of attributes whose combined values define its state. Their values also define which state transitions are allowed or not.
An object also has properties: these properties are derived from the attributes of the object, and the object's interface may have several operations that give the ability to its client to ask for the values of its properties.  Nevertheless, due to encapsulation, the object's properties (exposed, public, external) may be different from its attributes (hidden, private/protected, internal).
As the state of the object is defined by its attributes, it is sufficient to persist the values of these attributes to be able to rebuild the object later: read these attributes from the persistent store and set their values on a new instance of the same class as the original object.

A use-case for ORMs

In this whole story, the client of the object has no idea what the values of its attributes are.  The client is thus not able to know what to store.  This means that only components which know about the internals of the object are able to determine what attributes have to be persistently stored.
This is what an ORM does.  This is what Hibernate/OpenJPA/EclipseLink/TopLink, and eventually any JPA implementation do.  An ORM knows about the internal attributes of the objects that it persists into a relational data store.  The client asks the ORM to store or retrieve the object, and the ORM does it. The client does not need to know the internals of the object to execute operations provided by the ORM. In many cases, the ORM will even automatically synchronise the in-memory's object's state with the persistent data store, latest just before the end of the transaction.  This makes sense, as the client actually does not really know if and how the object's internal state has changed, and thus has no way to know whether the persisted object's state must be updated or not.
ORMs permit us to leverage object orientation, with its powerful encapsulation, when we design a domain model. This is the actual use-case for an ORM.

Do we need ORMs?

The anemic domain model

In the Java world (at least), most systems use what Martin Fowler calls an anemic domain model: domain models consist of classes that are composed of attributes which are exposed as properties, using the well-known getter and setter methods.  These objects also usually lack operations that represent its actual state transition and which encapsulate (and hide) how the state transition occurs: to change the state of an object, instead of requesting a state transition using one of the operations exposed by the object's interface, the client usually just sets the value of the object's attributes.
In this world (our world, the real world), such anemic domain objects have no more features that a structure in C programming language. In this case, one could wonder why setters and getters are needed to expose the object's attributes (which are usually private) instead of making these attributes public.  In fact, with recent versions of Hibernate, there is no justification for this.  First versions of Hibernate were not able to directly set/get the values of attributes with reflexion (and needed getter/setter methods), but this is no more the case.

Service operations as transaction scripts

As we are relying on the anemic domain model, service operations (the ones that define the boundaries of a transaction) usually consist in retrieving objects and changing their attributes by executing a series of setters of these objects.
This actually means that the service operation does de-facto know what will be persisted, and just specifies this in the object. Latest at the end of the service operation, just before the transaction is committed, the ORM framework will execute SQL INSERT/UPDATE/DELETE statements in order to persist the new values specified by the service operations using the setter methods. (This is actually why Hibernate is a framework: you don't always need to call it, it will automatically synchronise the in-memory object state with the persisted data).
Actually, here, the service operation doesn't need to rely on an ORM to persist the objects, as there is no encapsulation: there is no hidden/encapsulated attribute that the service ignores.
A completely equivalent way to implement the service is to let the service execute itself the series of SQL statements to update the object's persisted state.  This situation is fundamentally different from using an ORM, but with an equivalent outcome regarding the persisted state.

The fundamental differences between ORMs and other data access frameworks or libraries

ORMs are complex frameworks, which do many complex things under the hood in order to persist objet state and retrieve it.  It behaves like it is magic. Magic is difficult to control and to learn. ORMs are difficult to control and to learn. Do you need this in your software?
Remember your use-cases for persistence: store an object's state and retrieve it.
OK, ORMs can do this, but they are quite complex.  Another solution is to have your service operations execute SQL statements (using a Repository/DAO class for this is OK, but not really requested - this discussion is out of scope for this article). Doing this, you have full control of what happens in your software. You don't need to spend years using the ORM to finally understand how it works. There is no more magic. There is just the complexity required by your code's business.
Other impacts of using an ORM:
  • If you specify that an attribute is lazily loaded, then it will always be lazy-loaded, whatever your use-case. But actually, lazy-loading would make sense in some use-cases, while in others, it would not. With an ORM, you have to make a choice (lazy or eager loading) and then you must stick to it for all your use-cases.
  • ORMs work on an object graph: they cascade some operations (you may specify this) and they load a graph of objects, starting from the root object and then traversing the graph using SQL JOIN statements.  If you just need the root object, you'll get the whole graph, for free. Does this always make sense? Well, it depends on the specific use case.  This also brings its set of problems (n+1 selects, for example).
  • The JPA specification does not define the behaviour of the ORM if two classes are mapped on the same table: this implies that you should have one class per table, if you want guaranteed behaviour.
  • The exact generated SQL code depends on the implementation of the ORM, and there is no guarantee that the generated code does not change between versions of the same ORM: you change the version of your ORM, and suddently, your application could become very fast, or very slow, and this is out of your control.

Conclusion

As Martin Fowler documented it, we usually do not apply object orientation, and rather use an anemic domain model. Given this, we also usually implement service operations as transaction scripts.  In this case, is there still a reason to use ORMs? I am not sure of it.
There are many ways to access relational data: directly using JDBC (I wouldn't recommend this in most cases), Spring's JDBC template, MyBatis... you name it.
Usually, these tools all permit to work with different projections of the same entity, which de-facto means that you can put the data of one table into different classes (one per projection), while this is not possible with JPA implementations (at least).
These tools do work with objects, but just as a means to avoid having to work with JDBC's result set and as a means to specify SQL statement parameters using object attributes.  No magic behaviour is involved with these tools - at least nothing that impacts the client of these frameworks.
You will be in full control of the executed SQL code, and when the code is executed. You will be in full control of how the data is updated (no useless attributes updated, no object graph traversal to find modified objects/attributes - or however this is implemented) or retrieved (no useless attributes, no useless SQL JOINs...), and it will correspond to your use-case's requirements (and not to a choice you made because of another use-case).
Provided the whole world uses anemic domain models, is there still a good reason to use ORMs? Systems using domain models which leverage encapsulation justify the use of an ORM.
For other use cases, what is the added value of using ORMs?

2015-04-28

Oracle Metadata Services - oramds:/ URIs

Oracle Metadata Services (short: Oracle MDS, or simply MDS) is a proprietary repository delivered as part of Oracle Fusion Middleware BPM Suite, whose purpose is to store the resources (WSDL, XSD, BPMN,...) used in BPM solutions and to make them available to SOA development teams during design time as well as to SOA services at runtime.

The fact that it is proprietary makes the MDS have at least the following caracteristics:
  • It is well integrated into the tools suite provided by Oracle: Weblogic, JDeveloper BPM Suite.
  • It is absolutely not well (even virtually not at all...) integrated to other technologies (opensource or commercial), so it may become at some point in time a source for vendor locking, making it hard to switch from Oracle SOA solution to any other SOA solution (opensource or commercial).
In my eyes, vendor locking is a risk you have to mitigate when you want to use proprietary software, and concerning the MDS, it is the main risk.
To avoid vendor locking, it is essential to clearly assess your needs in terms of resource repository, development procedures and operations procedure, followed by the evaluation of the tradeoffs you are ready to accept before deciding to use the Oracle MDS.

As with any software technology, what is essential is to understand the interface (as in API, or service contract) of the solution, as your development and operations procedures, tools and files may be impacted by this interface.

So what is part of the Oracle MDS interface? At least the following:
  • The interface provided by JDeveloper: this is the integration with JDeveloper, which makes it easy to use the MDS and is the primary interface to the MDS.
  • The interface provided by Weblogic (BPM suite): this is the integration with Weblogic.  Multiple MDS services may be configured in Weblogic and may be used by deployments at runtime.
  • The files that are shared in the MDS: by default, some file types are modified when stored in the MDS.
    • XSD files: these are not modified by the MDS, provided they are stored in the same structure as in your filesystem.  XSD files may import other XSD files.  When you design your XSD files upfront, and store them in a specific filesystem hierarchy, the imports ideally use relative paths.  If you keep the same "directory" structure in the MDS, these imports will not need to be modified.  This is perfectly fine.
    • WSDL files: these may import several XSD files.  When you create WSDL files in JDeveloper, and import these into the MDS, the probability is high that JDeveloper has generated the paths to the imported XSD like "oramds:/BusinessObjects/MyObject.xsd".  In my opinion, this is absolutely not acceptable.  Because once the oramds:/ scheme is used in the WSDL, it is almost impossible to reuse the WSDL and XSDs as is with another tool, without modifying them to remove the oramds:/ scheme.
      • Eclipse does not understand oramds:/
      • Nor does CXF's wsdl2java
      • Nor does .Net
      • Nor does PHP
      • Nor does any other tool
        • This looks to me like a very serious source of vendor lock-in.
Nevertheless, there is a simple way to avoid having WSDLs containing the oramds:/ scheme, by adopting a top to bottom approach (WSDL first, contract first):
  • Generate your XSDs and WSDLs outside JDeveloper (thus, with Eclipse, XMLSpy, IntelliJ, Notepad++, or any other tool).
  • Organize them well in the filesystem folder.
  • Copy this filesystem folder inside the "SOA Design Time Repository" MDS instance of JDeveloper.
  •  Finally start designing your composites and processes using these WSDLs and XSDs from the MDS.
The WSDLs and XSDs will then be unmodified and will not have any oramds:/ paths.  You'll then be free to reuse the WSDLs and XSDs from any other tool.

For easy sharing between teams, you may also package your resources (WSDL, XSD,...) inside a JAR and distribute it using a common Maven repository.  Developers would then only need to unzip these JARs inside their "SOA Design Time Repository" MDS folder to import them and be ready to use them from JDeveloper.

2015-04-23

Oracle FMW - Exposing a SOAP WS with explicit header (multiple parts) as REST

SOAP messages may have multiple parts, located either in the SOAP message body or in the SOAP message headers.

Oracle FMW supports exposing SOAP WS with a single part as REST, but does not support exposing SOAP WS with multiple parts as REST.
In the latter case, JDeveloper BPM Studio recommends to use some mediator component which will be used to transform the multipart SOAP message into a single part one, then exposing this single part service.

This is of course not as elegant as to immediately expose the multipart service, yet it provides a not too complex technical solution to an issue which is probably due to concepts mismatch.

I guess the real issue lies in the fact that a message part may have arbitrary complex contents, may be placed inside the SOAP header and that there is no real corresponding header-place in HTTP for such complex structures as a SOAP message part.  Thus Oracle probably decided not to decide how to handle this situation, and to let the developers choose by themselves, which is also good.

Nevertheless, I believe the ideal solution would have been to support two ways to do it:
  • The current one, where the developer chooses how to handle multiple SOAP message parts
  • A second one, where Oracle would by default create a list of JSON parts in the HTTP payload, so that the developer would not be obliged to handle each single case using an additional mediator component.

2015-04-08

History of software architecture


Since its early days, the activity of defining software architectures has evolved to a common software engineering practice, whose foundations nowadays rely on widely adopted concepts. The definition and adoption of these concepts took place over multiple decades, one of the first serious works about software architecture being published in the year 1974 by David Parnas.

This article relates the evolution of the software architecture practice since its first days and how today’s commonly used concepts have been defined.

General concepts

In 2000, the IEEE adopted the IEEE 1471-2000 standard for the architectural description of software systems. This standard is now known as ISO 42010:2007, and has been updated in 2011 to ISO 42010:2011.
The ISO 42010 standard proposes (ISO 42010, 2011, pp. 1-2) widely accepted definitions for various concepts related to the documentation of software systems architecture.
Definition: Architecture of a system
The architecture of a system is the set of “fundamental concepts or properties of a system in its environment, embodied in its elements, relationships, and in the principles of its design and evolution.” (ISO 42010, 2011, p. 2)
Bass, Clements, and Kazman (2013) define the architecture of a software system: “The software architecture of a system is the set of structures needed to reason about the system, which comprise software elements, relations among them, and properties of both” (Bass et al., 2013, p. 4).  Compared to the definition of the standard ISO 42010, this definition emphasizes the utility of the architecture think globally about the system: documenting software architecture only makes sense if the documentation is actually used to reason about the architecture.
Other definitions exist, nevertheless the definitions provided by the ISO 42010 and Bass et al. (2013) remain valid in project using agile methods or spiral lifecycle methods, where the expression of requirements and therefore the definition of the architecture takes place during the whole lifetime of the project or iteratively.
Definition: Architecture description
An architecture description is the “work product to express an architecture” (ISO 42010, 2011, p. 2).
Generally speaking, an architecture description is used to express the properties of an architecture: ISO 42010 does not determine the contents of the architecture description.
Definition: Architecture framework
An architecture framework is the set of “conventions, principles and practices for the description of architectures established within a specific domain of application and/or community of stakeholders” (ISO 42010, 2011, p. 2).
According to ISO 42010 (2011, p. 9), an architecture framework establishes a common practice for the creation, the interpretation, the analysis and the usage of architecture descriptions in a specific application domain or by a specific stakeholder community.

The definition process of an architecture framework consists of defining the conventions, principles and practices which will be applied when describing an architecture.

History

It’s in the year 1974 that David Parnas noted that software systems are composed of many structures, and modelled a software system as the set of its parts and their inter-relationships (Parnas, 2000).
In 1992, Perry DeWayne and Alexander Wolf recognize the need for various views of a system (Perry & Wolf, 1992).
Definition: Architecture view
An architecture view is a “work product expressing the architecture of a system from the perspective of specific system concerns” (ISO 42010, 2011, p. 2).
In other words, an architectural view expresses the architecture of a system according to a perspective related to specific responsibilities of the system. Each architectural view of a system tries to describe a specific set of issues of the system. The definition given by ISO 42010 emphasizes the fact that an architectural view describes a specific set of issues, in contrary to the definition of Clements et al. (2011, p. 22) who stipulates: “A view is a representation of a set of system elements and the relationships associated with them”. The fundamental utility of views relies on the fact that it is very difficult to capture the whole set of properties of an architecture in its description. The documentation of views helps focus the effort on the essential features of a system’s architecture.
The concept of architectural view having been introduced, it becomes important to find out which architectural views are relevant in the description of a system’s architecture.
In 1995, Philippe Kruchten wrote an article describing four main views of software systems architecture: logical, process, development, physical. A fifth view links these four views by showing how they satisfy the key use cases. This 4+1 approach constitutes the fundaments of the well-known Rational Unified Process (RUP) method (Kruchten 1995).
Note: The logical view represents the functional structures of the system, the process view represents the concurrency and synchronization aspects of the system, the development view represents the modules, sub-systems, layers and issues directly related to the development, and finally the physical view identifies the nodes on which the system will be executed and the relationship of other architectural elements to these nodes (Rozanski & Woods, 2012, pp. 621-622).

It’s also in 1995 that Soni, Nord and Hofmeier define the Siemens Four View model for architecture, which contains the views conceptual, module interconnection, execution, code (Bass et al., 2013, p. 24). This model is noteworthy because it presents viewpoints in a precise and concrete manner, with more details than a simple digest of the information that a viewpoint must contain.
Note: The conceptual view represents the formal structures of the system, the module view represents the concrete components of the system, the execution view represents the processes, the threads, the inter-process communication mechanisms etc., and the code view represents the organization of the source code and the binary deliverables generated from the source code.

The concept of viewpoint has been, since 1995, a fundamental concept in the field software systems architecture descriptions.
In 2000, IEEE 1471-2000 recommends defining the architectural views which best serve and address the concerns of the stakeholders of the described system, but does not define a fixed set of architectural views, as such sets are very specific to the system and its stakeholders.

IEEE 1471-2000 used the concept of viewpoint, which was kept by the ISO 42010:2007 standard and then later adapted by the ISO 42010:2011 standard:
Definition: Architectural viewpoint
A viewpoint is “a work product establishing the conventions for the construction, interpretation and use of architecture views to frame specific system concerns” (ISO 42010, 2011, p. 2).

Note: It is Ross who introduced in 1977 the concept of viewpoint as an essential concept for the first time in his article Structured Analysis (SA): a language for communicating ideas, (ISO 42010, 2011, p. 21). It’s only twenty years later that this concept begins to be widely used, to the point of being reused in various standards.

A viewpoint describes the form and type of contents that a view must provide. The description of an architectural view must therefore match the specification given by the corresponding viewpoint. One may think of the architectural viewpoint as the contract which must be fulfilled by the architect when he or she documents an architectural view and which helps stakeholder understand and interpret this view.
In practice, a viewpoint may define a template which will be used by the architect to describe the corresponding view.
Various other view sets have been defined thereafter, amongst which the one defined by Rozanski and Woods (2012), which suggests to use the viewpoints context, functional, information, concurrency, development, deployment, operational and the use of the main architectural perspectives security, performance and scalability, availability and resilience, evolution (amongst other perspectives).
In 2002, the Software Engineering Institute (SEI) introduces the approach Views and Beyond. This approach begins by identifying the suitable architectural styles for the system being designed, followed by their application on the system, which results in an architectural view for each identified style. This approach defines three style categories, also name viewtypes: component and connector, module, allocation. The concept of viewtype matches ISO 42010’s concept of viewpoint. An architectural style defines how a specific architectural structure must be documented.
In 2005, Rozanski and Woods (2011) have defined the concept of architectural perspective:
Definition: Architectural perspective
An architectural perspective is a collection of architectural activities, tactics and guidelines that are used to ensure that a system exhibits a particular set of related quality properties that require consideration across a number of the system’s architectural views.” (Rozanski & Woods, 2012, p. 47).
According to Rozanski and Woods (2012, p. 47), the concept of architectural perspective is transversal to the concepts of views and viewpoints: the application of a perspective on the various architectural views ensures that a software system actually exhibits its desired qualities. The standard ISO 42010 does not define an equivalent concept to the one of architectural perspective, but proposes to reuse the models shared by multiple views to express architectural perspectives (ISO 42010, 2011, p. 14). 

The issues addressed by the architectural perspectives are often called non-functional requirements or cross-cutting concerns.
The required quality properties of a system’s architecture are rarely expressed by functional requirements. For the architect, it is appropriate to determine, with the stakeholders, which quality properties the system must exhibit. These quality properties are often influenced by a small amount of requirements, which are often of non-functional nature.

Note: In practice, it’s easy to develop a feature in many ways, using different concepts and technologies. Yet the desired quality properties of a software system will only be present if its design is appropriate: therein lies the whole problem of software systems architecture.

In 2003, Bass et al. (2013, p. 306) proposed to use a utility tree to determine the architecturally significant requirements and to determine their business value as well their impact on the architecture.
Definition: Architecturally significant requirement (ASR)
An architecturally significant requirement (ASR) is a requirement that will have a profound effect on the architecture that is, the architecture might well be dramatically different in the absence of such a requirement.” (Rozanski & Woods, 2012, p. 291)
Figure 1: Example of a utility tree. Note that a utility tree may contain more quality properties whose use really depends on the system being considered.

At the center of the utility tree lies the root node Utility. This node is then detailed, by connecting it to main quality properties (portability, function, reliability, usability, efficiency and maintainability). Each of these nodes is also connected to more detailed quality properties. Then, each of these quality properties is connected to the expression of one or more ASRs. Each ASR is labeled with an indicator of its business value and with its impact on the architecture.

Conclusion

To me, the key rules in software architecture documentation are the following
  • Architecturally significant requirements (ASRs) must be identified and must always be considered in every step of your design and documentation;
  • It is not possible to describe a system completely;
  • It is not necessary to describe a system completely.
So it is essential to identify the system's stakeholders, to identify their needs and to stick to these needs.  They should be the only actual drivers in your software architecture documentation practice.
These needs may be captured and documented into templates (the viewpoints), which will later be used to create the views of the system (remember, the viewpoint defines what must be documented in a view). In a specific environment, the viewpoints almost remain the same for all systems (obviously, they only change with the stakeholders and their needs).
If you are interested in architecture, have a look at the references used to write this article as well as to the TOGAF framework (http://www.togaf.org), which is an enterprise architecture framework, but which also clearly depicts the steps to take when building an architecture capability in an organization, including a software architecture capability.

References

  • Bass, L., Clements, P., & Kazman, R. (2013). Software architecture in practice (3rd ed. ; Software Engineering Institute, Carnegie Mellon, Ed.). Boston, USA : Pearson Education, Inc.
  • Clements, P., Bachman, F., Bass, L., Garlan, D., Ivers, J., Little, R., . . . Staffort, J. (2011). Documenting software architectures : views and beyond (2nd ed. ; Software Engineering Institute, Carnegie Mellon, Ed.). Boston, USA: Pearson Education, Inc.
  • IEEE Recommended Practice for Architectural Description of Software-Intensive Systems (Norm No IEEE Std 1471-2000). (2000). The Institute of Electrical and Electronics Engineer, Inc., New-York, USA.
  • Kruchten, P. B. (1995). The 4+1 view model of architecture. IEEE SOFTWARE, 12, 42–50.
  • Parnas, D. L. (2001). Software fundamentals : collected papers by David L. Parnas. In D. M. Hoffman & D. M. Weiss (Eds.), (pp. 139–148). Boston, MA, USA : Addison-Wesley Longman Publishing Co., Inc.
  • Rozanski, N., & Woods, E. (2012). Software systems architecture : working with stakeholders using viewpoints and perspectives (2nd ed.). USA : Pearson Education, Inc.
  • Systems and software engineering - Architecture description (Norm No ISO/IEC/IEEE 42010). (2011). International Organization for Standardization, Geneva, Switzerland, The Institute of Electrical and Electronics Engineer, Inc., New-York, USA.
  • Perry, D. E., & Wolf, A. L. (1992, October). Foundations for the study of software architecture. SIGSOFT Softw. Eng. Notes, 17(4), 40–52. Consulted on http://doi.acm.org/10.1145/141874.141884 doi : 10.1145/141874.141884

Interesting links