Sunday, August 14, 2016

Hyperlinks with PDFBox-Layout

One thing that made HTML so successful is the hyperlink. Keywords are marked up, and just by clicking on them, you are redirected to the refrerenced position in the document, or even to some totally different document. So it makes perfect sense to use hyperlinks in PDF documents also. Whether you are linking the entries of a TOC to the corresponding chapter, or a piece of information to a corresponding URL in wikipedia. Linking text enriches the content, and makes it more usable.

Luckily PDF (and PDFBox) supports hyperlinks, so why not use it? Because it's a pain. The PDF standard has no notion of marked up text, but the more general and abstract idea of annotated areas: You can describe some area in the document by coordinates, and add some metadata telling the PDF reader what to do with that area. That's quite powerful. You can do highlighting and all kinds of actions with that, and totally independant of the content, just by describing an area. And that's also the catch: it is totally independent of the content. If you are used to the notion of marked up text, this feels a bit unhandy. Let me give you an example how to do a link:

PDDocument document = new PDDocument();

PDPage page = new PDPage();
document.addPage(page);
float upperRightX = page.getMediaBox().getUpperRightX();
float upperRightY = page.getMediaBox().getUpperRightY();

PDFont font = PDType1Font.HELVETICA;
PDPageContentStream contentStream = new PDPageContentStream(document, page);
contentStream.beginText();
contentStream.setFont(font, 18);
contentStream.moveTextPositionByAmount( 0, upperRightY-20);
contentStream.drawString("This is a link to PDFBox");
contentStream.endText();
contentStream.close();

// create a link annotation
PDAnnotationLink txtLink = new PDAnnotationLink();

// add an underline
PDBorderStyleDictionary underline = new PDBorderStyleDictionary();
underline.setStyle(PDBorderStyleDictionary.STYLE_UNDERLINE);
txtLink.setBorderStyle(underline);

// set up the markup area
float offset = (font.getStringWidth("This is a link to ") / 1000) * 18;
float textWidth = (font.getStringWidth("PDFBox") / 1000) * 18;
PDRectangle position = new PDRectangle();
position.setLowerLeftX(offset);
position.setLowerLeftY(upperRightY - 24f);
position.setUpperRightX(offset + textWidth);
position.setUpperRightY(upperRightY -4);
txtLink.setRectangle(position);

// add an action
PDActionURI action = new PDActionURI();
action.setURI("http://www.pdfbox.org");
txtLink.setAction(action);

// and that's all ;-)
page.getAnnotations().add(txtLink);

document.save("link.pdf");



Ouch, this ain't no fun. Ok, I see you have all freedom to markup whatever you want. And you can do real fancy stuff with that, like highlight things, adding tooltips and a lot more. But if you just wanna add a hyperlink... hmmm. Let's do that again with PDFBox-Layout:

Document document = new Document();

Paragraph paragraph = new Paragraph();
paragraph.addText("This is a link to ", 18f,
PDType1Font.HELVETICA);
 
// create a hyperlink annotation
HyperlinkAnnotation hyperlink = 
   new HyperlinkAnnotation("http://www.pdfbox.org", LinkStyle.ul);

// create styled text annotated with the hyperlink
AnnotatedStyledText styledText = 
   new AnnotatedStyledText("PDFBox", 18f,
                           PDType1Font.HELVETICA, Color.black,
                           Collections.singleton(hyperlink));
paragraph.add(styledText);
document.add(paragraph);

final OutputStream outputStream = new FileOutputStream("link.pdf");
document.save(outputStream);

This performs exactly the same things. But you just say what you want: add a hyperlink to the given text. And all this odd area marking boilerplate code is handled by PDFBox-Layout. And we can do even better using markup:

Document document = new Document();

Paragraph paragraph = new Paragraph();
paragraph.addMarkup(
   "This is a link to {link[http://www.pdfbox.org]}PDFBox{link}", 
   18f, BaseFont.Helvetica);
document.add(paragraph);

final OutputStream outputStream = new FileOutputStream("link.pdf");
document.save(outputStream);

We just markup the text with the hyperlink URL and that's it :-) So now we can do external URLs, what about links into the document itself? Let's take the example Links.java. In order to link to some point in the document we have to add an anchor to this position. After that we can link to that anchor using the anchors name:

paragraph0.addMarkup(
   "And here comes a link to an internal anchor name {link[#hello]}hello{link}.\n\n", 
   11, BaseFont.Times);

...
paragraph4.addMarkup(
   "\n\n{anchor:hello}Here{anchor} comes the internal anchor named *hello*\n\n", 
   15, BaseFont.Courier);

So we define an anchor "{anchor:hello}Here{anchor}" somewhere in the document with the logical name `hello`. This anchor name is used in the link prefixed with a hash to indicate an internal link "{link[#hello]}hello{link}". See the example PDF links.pdf for the results. And that's all to say about links. Hopefully easy to use, and the dirty work is done behind the scenes by PDFBox-Layout.

Regards
Ralf
A chain is no stronger than its weakest link,
and life is after all a chain.
William James

Monday, June 13, 2016

Creating Lists with PDFBox-Layout

The last article gave you a brief introduction on what you can do with PDFBox-Layout. The new release 0.6.0 added support for indentation and lists, and that’s what this article is about.

Indentation

Indentation is often used to structure content, and it is also the base for creating lists. Let’s start with some simple example using the Indent element.

paragraph.addMarkup(
    "This is an example for the new indent feature. Let's do some empty space indentation:\n",
        11, BaseFont.Times);
paragraph.add(new Indent(50, SpaceUnit.pt));
paragraph.addMarkup("Here we go indented.\n", 11, BaseFont.Times);
paragraph.addMarkup(
    "The Indentation holds for the rest of the paragraph, or... \n",
    11, BaseFont.Times);
paragraph.add(new Indent(70, SpaceUnit.pt));
paragraph.addMarkup("any new indent comes.\n", 11, BaseFont.Times);

So what do we do here: we add an indent of 50pt width. This indent will be automatically inserted after each newline until the end of the paragraph…or a new indent is inserted. That’s what we do here, we insert an indent of 70pt:

indention

An indent may also have a label (after all, this is the foundation for lists). By default the label is right aligned, as this makes sense for lists. But you may specify an alignment to fit your needs:

paragraph = new Paragraph();
paragraph
    .addMarkup(
        "New paragraph, now indentation is gone. But we can indent with a label also:\n",
        11, BaseFont.Times);
paragraph.add(new Indent("This is some label", 100, SpaceUnit.pt, 11,
    PDType1Font.TIMES_BOLD));
paragraph.addMarkup("Here we go indented.\n", 11, BaseFont.Times);
paragraph
    .addMarkup(
        "And again, the Indentation holds for the rest of the paragraph, or any new indent comes.\nLabels can be aligned:\n",
        11, BaseFont.Times);
paragraph.add(new Indent("Left", 100, SpaceUnit.pt, 11,
    PDType1Font.TIMES_BOLD, Alignment.Left));
paragraph.addMarkup("Indent with label aligned to the left.\n", 11,
    BaseFont.Times);
paragraph.add(new Indent("Center", 100, SpaceUnit.pt, 11,
    PDType1Font.TIMES_BOLD, Alignment.Center));
paragraph.addMarkup("Indent with label aligned to the center.\n", 11,
    BaseFont.Times);
paragraph.add(new Indent("Right", 100, SpaceUnit.pt, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("Indent with label aligned to the right.\n", 11,
    BaseFont.Times);
document.add(paragraph);

indentionWithLabel

Lists

As already said, indentations where introduced in order to support list, so let's build one. It's nothing but indentation with a label, where the label is a bullet character:

paragraph = new Paragraph();
paragraph.addMarkup(
    "So, what can you do with that? How about lists:\n", 11,
    BaseFont.Times);
paragraph.add(new Indent(bulletOdd, 4, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("This is a list item\n", 11, BaseFont.Times);
paragraph.add(new Indent(bulletOdd, 4, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("Another list item\n", 11, BaseFont.Times);
paragraph.add(new Indent(bulletEven, 8, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("Sub list item\n", 11, BaseFont.Times);
paragraph.add(new Indent(bulletOdd, 4, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("And yet another one\n", 11, BaseFont.Times);

list

Ordered Lists with Enumerators

Ordered lists are quite helpful to structure and reference text. You already have all ingredients to build an ordered lists; just use increasing numbers as labels, and that's it. What would I need an API for to do that?!? How about a list with roman numbers:
RomanEnumerator e1 = new RomanEnumerator();
LowerCaseAlphabeticEnumerator e2 = new LowerCaseAlphabeticEnumerator();
paragraph = new Paragraph();
paragraph.addMarkup("Also available with indents: Enumerators:\n", 11,
    BaseFont.Times);
paragraph.add(new Indent(e1.next() + ". ", 4, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("First item\n", 11, BaseFont.Times);
paragraph.add(new Indent(e1.next() + ". ", 4, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("Second item\n", 11, BaseFont.Times);
paragraph.add(new Indent(e2.next() + ") ", 8, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("A sub item\n", 11, BaseFont.Times);
paragraph.add(new Indent(e2.next() + ") ", 8, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("Another sub item\n", 11, BaseFont.Times);
paragraph.add(new Indent(e1.next() + ". ", 4, SpaceUnit.em, 11,
    PDType1Font.TIMES_BOLD, Alignment.Right));
paragraph.addMarkup("Third item\n", 11, BaseFont.Times);
document.add(paragraph);
enumerators
Enumerators ease the task of generating ordered lists programmatically (and the markup API could not live without 'em ;-). Currently the following enumerators are supported:
  • ArabicEnumerator (1, 2, 3, 4...)
  • RomanEnumerator (I, II, III, IV...)
  • LowerCaseRomanEnumerator (i, ii, iii, iv...)
  • AlphabeticEnumerator (A, B, C, D...)
  • LowerCaseAlphabeticEnumerator (a, b, c, d...)

Markup

The markup API eases the burden of creating features programatically, and for sure you can do indentation and lists with markup. We're gonna start with some simple indentation. You start the indentation with -- at the beginning of a new line:
"--At vero eos et accusam\n"

Indents run until the end of a paragraph, or until another indentation starts. But you can you can explicitly end the indentation with !-:
"-!And end the indentation.\n"
indentation-markup

The default indent is 4 characters, but you can customize this by specifying the desired indentation in pt or em, so the markup --{50pt} will give you an indent of 50pt. Be aware that this size is per indent level, so if you prefix a space, you will get 100pt in this case.

To create lists with bullets, use the -+ markup:
"-+This is a list item\n"
"-+Another list item\n"

You can specify different levels of indentation just be prefixing the indent markup with one or multiple spaces:
" -+A sub list item\n"

You can customize the indent size and the bullet character (after all, this is the indentation label). Let's do an indent of 8 characters and use >> as the bullet: -+{>>:8em}
list-markup

Enumerated lists are supported also, just use the -# markup:

"-#This is a list item\n"
"-#Another list item\n"
" -#{a:}A sub list with lower case letter\n"
"-#And yet another one\n\n"

enumerators-markup
Again, you can customize the indent size and also the enumeration type. The default type is arabic numbers, but let's use the roman enumerator: `-#{I:6em}. The following enumerator types are built in:
  • 1 arabic
  • I roman, upper case
  • i roman, lower case
  • A alphabetic, upper case
  • a alphabetic, lower case
So let's use some custom separators here:

"-#This is a list item\n"
"-!And you can customize it:\n"
"-#{I ->:5}This is a list item\n"
"-#{I ->:5}Another list item\n"
" -#{a ~:30pt}A sub list item\n"
"-#{I ->:5}And yet another one\n\n";
custom-lists-markup

But you may also write your own enumerator and use it in markup, see class EnumeratorFactoryfor more details on that.

Regards
Ralf
The human animal differs from the lesser primates in his passion for lists.
H. Allen Smith

Sunday, April 17, 2016

PDF text layout made easy with PDFBox-Layout

More than a decade ago I was using iText to create PDF documents from scratch. It was quite easy to use, and did all the stuff I needed like organizing text in paragraphs, performing word wrapping and marking up text with bold and italic. But once upon a time Bruno Lowagie - the developer of iText - switched from open source to a proprietary license for reasons I do understand.

So when I now had to do some PDF processing for a new project, I was looking for an alternative. PDFBox is definitely the best open source choice, since it is quite mature.But when I was searching on how to do layout, I found a lot of people looking for exactly those features, and the common answer was: you have to do it on your own! Say what? Ouch. There must be someone out there, who already wrote that stuff... Sure there is, but google did not find him. So I started to write some simple word wrapping. And some simple pagination. And some simple markup for easy highlighting with bold an italic. Don't get me wrong: the stuff I wrote is neither sophisticated nor complete. It is drop dead simple, and does the things I need. But just in case someone out there may find it useful, I made it public under MIT license on GitHub.

column


PDFBox-Layout

PDFBox-Layout acts as a layer on top of PDFBox that performs some basic layout operations for you:
  • word wrapping
  • text alignment
  • paragraphs
  • pagination
The API actually has two parts: the (low-level) text layout API, and the document layout API.

The Text Layout API

The text layout API is thought for direct usage with the low level PDFBox API. You may organize text into blocks, do word wrapping, alignment, and highlight text with markup. Means: most features described in the remainder of this article may be used directly with PDFBox without the document layout API.  For more details on this API see the Text API Wiki page. What the document layout API gives you as a surplus, is paragraph layout and pagination.

The Document Layout API

The ingredients of the document layout API are documents, paragraphs and layouts. It is thought to easily create complete PDF documents from scratch, and performs things like word-wrapping, paragraph layout and pagination for you.
Let's start with a simple example:

document = new Document(Constants.A4, 40, 60, 40, 60);

Paragraph paragraph = new Paragraph();
paragraph.addText("Hello Document", 20, PDType1Font.HELVETICA);
document.add(paragraph);

final OutputStream outputStream = 
    new FileOutputStream("hellodoc.pdf");
document.save(outputStream);

We start with creating a Document, which acts as a container for elements like e.g. paragraphs. You specify the media box - A4 in this case - and the left, right, top and bottom margin of the document. The margins are applied to each page. After that we create a paragraph which is a container for text fragments. We add a text "Hello Document" with the font type HELVETICA and size 20 to the paragraph. That's it, let's save it to a file. The result looks like this:

hello

Word Wrapping

As already said, you can also perform word wrapping with PDFBox-Layout. Just use the method setMaxWidth() to set a maximum width, and the text container will do its best to not exceed the maximum width by word wrapping the text:

Paragraph paragraph = new Paragraph();
paragraph.addText(
    "This is some slightly longer text wrapped to a width of 100.", 
    11, PDType1Font.HELVETICA);
paragraph.setMaxWidth(100);
document.add(paragraph);

wrapped1

If you do not specify an explicit max width, the documents media box and the margins dictate the max width for a paragraph. Means: you may just write text, write text and more text without the need for any line beaks, and the layout will do the word wrapping in order to fit the paragraph into the page boundaries.

Text-Alignment

As you might have already seen, you can specify a text alignment on the paragraph:
Paragraph paragraph = new Paragraph();
paragraph.addText(
    "This is some slightly longer text wrapped to a width of 100.", 
paragraph.setMaxWidth(100);
paragraph.setAlignment(Alignment.Right);
document.add(paragraph);

wrapped-right

The alignment tells the draw method what to do with extra horizontal space, where the extra space is the difference between the width of the text container and the line. This means, that the alignment is effective only in case of multiple lines. Currently, Left, Center and Right alignment is supported.

Layout

The paragraphs in a document are sized and positioned using a layout strategy. By default, paragraphs are stacked vertically by the VerticalLayout. If a paragraph’s width is smaller than the page width, you can specify an alignment with a  layout hint:

document.add(paragraph, 
    new VerticalLayoutHint(Alignment.Left, 10, 10, 20, 0));

You can combine text- and paragraph-alignment anyway you want:

aligned

An alternative to the vertical layout is the Column-Layout, which allows you to arrange the paragraphs in multiple columns on a page.

Document document = 
    new Document(Constants.A4, 40, 60, 40, 60);
 
Paragraph title = new Paragraph();
title.addMarkup("*This Text is organized in Colums*", 
    20, BaseFont.Times);
document.add(title, VerticalLayoutHint.CENTER);
document.add(new VerticalSpacer(5));

// use column layout from now on
document.add(new ColumnLayout(2, 10));

Paragraph paragraph1 = new Paragraph();
paragraph1.addMarkup(text1, 11, BaseFont.Times);
document.add(paragraph1);
...

column

But you may also set an absolute position on an element. If this is set, the layout will ignore this element, and render it directly at the given position:

Paragraph footer = new Paragraph();
footer.addMarkup("This is some example footer", 6, BaseFont.Times);
paragraph.setAbsolutePosition(new Position(20, 20));
document.add(paragraph);

Pagination

As you add more and more paragraphs to the document, the layout automatically creates a new page if the content does not fit completely on the current page. Elements have different strategies how they will divide on multiple pages. Text is simply split by lines. Images may decide to either split, or - if they fit completely on the next page - to introduce some vertical spacer in order to be drawn on the next page. Anyway, you can always insert a NEW_PAGE element to trigger a new page.

Markup

Often you want use just some basic text styling: use a bold font here, some words emphasized with italic there, and that's it. Let's say we want to use different font types for the following sentence:

"Markup supports bold, italic, and even mixed markup."

If you want to do that using the standard API, it would look like this:

Paragraph paragraph = new Paragraph();
paragraph.addText("Markup supports ", 11, PDType1Font.HELVETICA);
paragraph.addText("bold", 11, PDType1Font.HELVETICA_BOLD);
paragraph.addText(", ", 11, PDType1Font.HELVETICA);
paragraph.addText("italic", 11, PDType1Font.HELVETICA_OBLIQUE);
paragraph.addText(", and ", 11, PDType1Font.HELVETICA);
paragraph.addText("even ", 11, PDType1Font.HELVETICA_BOLD);
paragraph.addText("mixed", 11, PDType1Font.HELVETICA_BOLD_OBLIQUE);
paragraph.addText(" markup", 11, PDType1Font.HELVETICA_OBLIQUE);
paragraph.addText(".\n", 11, PDType1Font.HELVETICA);
document.add(paragraph);

That's annoying, isn't it? That's what the markup API is intended for. Use * to mark bold content, and _ for italic. Let's do the same example with markup:

Paragraph paragraph = new Paragraph();
paragraph.addMarkup(
    "Markup supports *bold*, _italic_, and *even _mixed* markup_.\n", 
    11, 
    PDType1Font.HELVETICA, 
    PDType1Font.HELVETICA_BOLD,
    PDType1Font.HELVETICA_OBLIQUE,
    PDType1Font.HELVETICA_BOLD_OBLIQUE);
document.add(paragraph);

To make things even more easy, you may specify only the font family instead:

paragraph = new Paragraph();
paragraph.addMarkup(
    "Markup supports *bold*, _italic_, and *even _mixed* markup_.\n",
    11, BaseFont.Helvetica);

markup


That’s it

This was a short overview on what PDFBox Layout can do for you. Have a look at the Wiki and the examples for more information and some visual impressions.

Monday, January 4, 2016

Avoid Vertical Limits in Microservice Architectures

The microservice architecture allows us to partition an application into tiny sub-applications, which are easy to maintain and to deploy. This pattern is already widely adopted to implement backend systems. But the frontend is usually still one large application, at least when it comes to deployment. This article describes some thoughts on how to address this problem.
The microservice architecture is en vogue, everybody seems to know all about it, and feels like having to spread the truth. Including me ;-) But honestly, we are just about to learn how to cope with this kind of architecture. I guess we are like a kid that just managed to make some first steps, when we suddenly try to start running… that’s usually the moment when you fall over your own feet. Microservices are no free lunch, it definitely has its price (that’s the part we have already learned). For developers it feels uncomfortable, since instead of developing one application, they have to deal with dozens or hundreds. Usually the microservice-believers are the people who drive and maintain an application over a long period of time; those poor chaps that know the pain of change. And that is were their trust – or better: hope – in microservices comes from.

So what is this article about? I’m currently working in a web project for a customer, where we are using Spring Boot to create a microservice-based backend. We heavily use the Job DSL to drive our CI pipeline, and also all kind of configuration and tooling. And the front end is a single page application built with AngularJS. So far, so good, but there is a catch. One goal of this microservice idea is to have independent development teams, that drive features within their own development cycle. In the backend this is feasible due to the microservice architecture. But the front end is still one large application. Angular allows to partition the application into modules, but after all it is assembled to one application, so this is a single point of integration. Let me explain that point using a practical example. It is a stupid-simple web shop, stripped down to the bones. It is just a catalog of items, which we can put into a shopping cart:



I have prepared the example as a Spring Boot based application in the backed, with some AngularJS in the frontend. You will find the code on GitHub, the version we start with, is on the branch one-ui. All projects have maven and gradle builds, the readme will provide you enough information to run the application.
Just some note before we start: I’m not a web developer. In the last 20 years I have build – beside backend systems – various UIs in Motif, QT, Java AWT, Swing and SWT. But I have never done web frontends, there has never been the chance or need for that. So please be merciful if my angular and javascript looks rather… er, surprising to you ;-)
The architecture of our stupid simple web shop looks like this:

initial2

The browser accesses the application via a router, which limits access to the backend, helps with the CORS problem, and may also perform some security checks. The web-server hosts the AngularJS application and the assets. The AngularJS application itself communicates with the API-Gateway, which encapsulates the microservices in the backend, and provides services and data optimized for the UI. The API-Gateway pattern is often used in order to not to bloat the microservices with functionality where it not belongs to. We will see its advantages later on. The gateway talks to the backend microservice, which then perform their dedicated functionality using their own isolated databases (the databases has been omitted for simplicity in the example code).

So far nothing new, what’s the point? Well, what is that microservice idea all about? Ease of change. Make small changes easy to apply and deploy. Minimize the risk of change by having to deploy only a small part of the application instead of a large one-size-fits-all application. In the backend this is now widely adopted. The microservices are tiny, and easy to maintain. As long as their interfaces to other services remain (compatible), we may replace them with a new version in a running production environment, without affecting the others. And – if done right – without downtime. But what about the frontend? The frontend is mostly still one large application. If we make a small change to the UI, we have to build and redeploy the whole thing. Even worse, since it is one application, bug fixes and features are often developed in parallel by large teams, which makes it difficult to release minor changes separately. At last, that’s what the microservice story is all about: Dividing your application into small sub-applications which can be developed and deployed separately, giving each its own lifecycle. And consequently, this pattern should be applied to the complete application, from database via services to the frontend. But currently, our microservice architecture thinking ends at the UI, and that’s what I call a vertical limit.

We investigated how other people are dealing with this situation, and – no wonder – there were a lot of complaints about the same problem. But surprisingly, most advices to address this were to use the API-Gateway… er, but this does not solve the problem?!? So let’s think about it: we are dividing our backend into fine grained microservices in order to cope with changes. Consequently, we should exactly the same in UI. We could partition our UI into components, where features make up the logical boundaries. Let’s take our silly vertical shop example to exercise this. We separate this UI at least into two logical components: the catalog showing all available items, and the shopping cart. Angular provides a mechanism to build components: directives! The cart and the catalog are already encapsulated in angular directives (what a coincidence ;-). So what if we put those parts each on its own web-server? Let’s see how our architecture would look like:

multipleUI_oneGateway2

Hmm, obviously the API gateway is still a common denominator. The gateway’s job is to abstract from the backend microservice and to serve the UI in the best suited way. So consequently, we should divide the gateway also. But since it so closely related to the UI, we are packaging ‘em both into one service in our example. Let’s do so, you will find the code for this version on the branch ui-components. Now the architecture looks like this:

 componentsDashed

Hey wait! I’ve had look at your UI code. It’s not just the directives, there are also angular services. And the add-button in the catalog directive is effectively calling addItem() on the cart-service. That’s quite true. But is that a problem? In our microservice backend, services are calling other services also. This is not a problem, as long as the service’ API doesn’t change, resp. remains compatible. The same holds on the javascript side. As long as our API doesn’t change (remains compatible), new service rolllouts and internal changes are not a problem. But we have to design these interfaces between components wisely: (angular) services may be used by other components, so we have to be careful with changes. Another way of communication between components is broadcasting events. Actually the cart component is firing an event every time the cart changes, in order to give other components a chance to react on that. So we have to be cautious with changes to events also. New resp. more data is not a problem, removing or renaming existing properties is. So we simply put all functionality dealing with the cart on the cart web-server, and the catalog stuff on the catalog web-server… including their dedicated directives, services, assets a whatsoever. Our communication looks like this:

communication

Big words and bloated architecture. It ain’t worth it! You think so? Let’s make a small change to our application and examine its impact: Our customer does not like our shopping cart: “It just shows each items article number, and its amount. That’s not quite helpful. The user needs the article’s name…its price…and the sum of all items in the cart.”


Well, yeah, she’s right. So let’s fix that. But the cart microservice does not provide more information. Article names and prices are the catalog service’ domain. So the cart service could call the catalog service and enrich its data? But that’s not the cart’s domain, it should not have to know about that. No, providing the data in a way appropriate for the UI is the job of the API gateway (finally it pays ;-). So instead of delegating all calls to the cart service, the cart’s API gateway merges the data from the cart with the catalog data to provide cart items with article names and prices:

cartGateway

Now we simply adapt the UI code of the cart in order to use and visualize this additional data. You will find the source code of this final version on the master. All changes we made are isolated in the cart UI resp. its API gateway, so we only have to redeploy this single server. Let’s do so. And if we now reload our application, tada:


So, we made a change to the shopping cart without affecting the remaining application. Without redeploying the complete UI. All the advantages we take the microservice-burden on our shoulders for, now pays in the front end also. Just treat your front end as a union of distinct features. In agile development it is all about features resp. stories, and now we we are able develop and release features in its own lifecycle. Hey wait, the index.html still assembles the cart and the catalog to a single page. So there is still a single point of integration! Yep, you’re right. This is still one UI, but we have componentized it. Once a component is referenced in a page, that’s it. Any further changes to internals of that component does not affect the hosting page. Our microservices are also referenced by other parties, so this is quite similar.

The point is to avoid vertical limits in this kind of architecture. We have to separate our application into small sub-applications in all layers, namely persistence, service backend and frontend. In the backend this cut is often domain-driven, and in the front end we can use features to partition our application. For sure there are better ways and technologies to implement that, but I guess this is a step into the right direction.
We learn from failure, not from success!
Bram Stoker

1) This was poor attempt to avoid the word monolith, which is – at the time of writing – mistakenly flavored with a bad smack.