Lessons from “Good enough” architecture

Definition of Architecture

According to ISO : “Architecture is fundamental concepts or properties of a system in its environment embodied in its elements, relationships and in the principles of its design and evolution.” . Well, smell of academy, I don’t like it .

The next explanation is make more senses : Architecture represents the significant design decisions that shape a system, where significant is measured by cost of change (Grady Booch).

And one important fact is, this is not the work of someone labeled themself “architecture” only. Architecture is not an upfront activity performed by somebody in charge of telling everyone else what to do.

Back to the academy definition, Architecture is a property of a system, not a description of its intended design. A system always has its architecture, intentionally or accidentally :))

So, What is Good Architecture

This is kinda an arrogance question. It’s likely to tell what is a good car or a good wife :>>. Mature man will say : “it depends” 😀

Any kind of Architecture must satisfy all Quality Properties. Academically, (ISO things), Quality Properties of a system/application are :

  • Functional Suitability –> Does your functions do what the customer want, many bugs or not ? :)))
  • Performance Efficiency –> How fast does your system response to users?
  • Compatibility –> How easy is it to integrate with other system or application?
  • Usability –> How easy for users to use your system?
  • Reliability –> Does an unexpected error shut down entire system, or a part ?
  • Security –> Can it be hacked ?
  • Maintainability –> Is it easy to change or add logic ? Do new guys understand source code easily?
  • Portability –> How easy to setup your system ?

So much to take care of for a single decision at a moment !! . But it depends on what kind of your application, what is the purpose that you can temporarily more care about one property than others or even sacrifice one or more properties to optimize others. Deadline & Budget are un-official properties according to ISO but no one can deny its significant effects on ensuring above properties :))).

It is all about Balancing

For example in Scaling system challenge : Everyone want their system “easy to scale”. Normally “Scale” term makes us think about a system like Facebook or Google with a half of planet users, but actually there are 3 dimensions when talk about scaling :

  • Logic Scaling: How complex is the business logic ? Is it written in a day or frequently changed depends on unknown conditions ?
  • Load Scaling: How many users ? Your system is going to serve a dozen of users or a haft of the Earth ?
  • Team Scaling: How many developers are working on it?

Logic Scaling often appears in B2B multi-tenancy CRM/ERP applications with highly customizability. As instinct, Architecture guys likely to decide to generalize everything by introducing configurations, settings, modules with on/off ability to satisfy all anticipated client needs and you may think that writing if/else for a certain clients is “hard code“.
The needs can be so general like button color, website logo, email template, etc, to very specific per client such as configuring workflow, assembling reports, employee task assigning logic, etc .. The more specific need, the more sophisticated configurations is, and the more complexity in source code. It is reducing Maintainability to enhance Functional Suitability.
It works for most cases but a fact is that this kind of applications often have a small group of big clients that pay well for features and customizations, and the rest just uses what are available. Soon or late, those big clients will request you to make some unique logics that totally different from others. Those kind of super specific requirements obviously adds super extra complexity to the source code. As a quick judgment, those extra complexity for a small set of users is NOT worthy, right? . But it worths as business perspective. So the beginning idea of generalizing everything is not perfect. You now wish for a method to put all specific logics for certain clients, to manage them easily, and the if/else code for certain clients turns out not a “hard code” anymore if it is put in the right place. It is the balancing between generalization versus specialization.

Load Scaling is the decision between Horizontal versus Vertical. As we know that there are 2 common ways to increase the load that a system endures :

  • Vertical method : add more RAM
  • Horizontal method : add more machines and apply load balancing techniques

Adding more RAM is the easiest way but the limitation is the maximum amount of RAM. Adding more machines solves vertical method limitation but it adds complexity to system. It is reducing Portability to enhance Performance Efficiency : more deployment effort than before.
But how about Horizontal method, does it have any drawback comparing to Vertical one? Yes, you mostly have to write more logics to synchronize session data when user connects to more than 1 instance, or logic to select the best instance to help users persistent connected with 1 instance. It may lead to more problems when the you are scaling the database, it adds more headaches when you want to index a few tables that located across multiple machines, or to handle relational operations in SQL type database , etc … It is reducing Maintainability to keep Performance Efficiency too.

Team Scaling often appears in large company with multiple teams and hundreds developers. Team Scaling is more about management problem than coding problem. Too much people need a strict process to co-operate to avoid trampling upon others, maximize team’s abilities and separate team’s responsibilities. The most popular architecture nowadays for Team Scaling is MicroServices where each team has their own tech stack if provide it can integrate with others. Each team can have its own system and they ensure Quality Properties themself, inside their boundary. So the entire system contains other small systems. This is reducing Portability to enhance Maintainability.

The most difficult decision when applying MicroService is to separate responsibilities between teams. Wrong separation leads to heavy or strict dependency between teams and it ruins every benefits offered by MicroServices, and even weaken Maintainability and Performance Efficiency comparing to traditional Monoliths Architecture.

Traditional Monoliths Architecture can deal with Team Scaling using Modulation. Each team handle a few modules, each module contains a or a few features. This way, every teams work on the same tech stack but different modules. The heavy or not dependency between modules is not a deal here because they are already compacted. This method keeps both Portability and Maintainability in contrast to MicroService but may reduce Performance Efficiency when the Load is high. This again backs to Load Scaling problem.

Another example is Banking systems. Their most important properties is Security and they willing to decrease their Performance Efficiency, Maintainability and Portability to make the transaction more secure, more idempotent by using transactional queries, install more filter, IDS/IPS, etc. We can’t judge them as a “Not Good” architecture just because our CMS system serves APIs faster.

Don’t bias to anything. Everything has its own pros and cons. Understand them and use them wisely.

There is no good or bad thing, there is only “good enough”

Stop using java.util.Date

I used to leverage java.util.Date class to store and represent date time data but I suffered a lot from many problems due to java.util.Date’s limitations itself.

In fact I am not alone. Many people suffer too. Here is an article about java.util.Date that I think it covers enough : https://codeblog.jonskeet.uk/2017/04/23/all-about-java-util-date/. Below is the summary, it’s limitations are :

  • A Date instance represents an instant in time, not a date. It is basically a long number that we call timestamp. This brings more headaches while reading data, debugging and conversion this timestamp to actual date.
  • It doesn’t contain time zone information. The toString() of java.util.Date is sticked with executing system timezone. You will get different dates in different machines in different timezones. This may confuse your customer when you want to show your java.util.Date as a string. Developers also have to pay more attention about system current timezone while writing code and most of time, they forgot.
  • It doesn’t have a format. This brings many ambiguities when conversing data from string and vice versa.
  • It doesn’t have a calendar system. It means it does not guarantee that a java.util.Date will return correctly information about day of week , etc which is useful when you want to check about weekend or holidays.

As the conclusion in the above link, and as my point of view too, we should avoid to use java.util.Date as much as possible, especially when your application gonna run over multiple timezones. Oracle perceives this painful and they did release new libraries for date time : DateLocal & DateTimeLocal in Java8. They are a great libraries to use but while databases still do not work with those new ones – they still uses timestamp (old java.util.Date) to represent a Date column, we have to cure ourself.

My problems with java.util.Date

I am a full-stack developer. In my company, we build server by pure Servlet, deploy using Google Cloud Platform and use GWT for front-end. GWT is old now but this system is built from the day GWT gets it trend, about 2012. The big advantage that GWT brings to us is it allows Java developer to create UI by Java. The fact is that we built a complete full-stack framework based on Java.

Our database is Datastore which is provided by Google and the official tutorial tells us to store date time data by setting a java.util.Date instance to the entity. Then after a year, we got reports from users that their inputed date times are displayed wrong, usually 1 hour backward or forward. I started investigations and this is what I found out :

When creating DateTimeInput class, we have 2 options to implement :

  • Get value & set value by a String
  • Get value & set value by a timestamp

If we know about how ambiguous the timestamp is, we will choose String . But unfortunately, we decided to use timestamp because a naive thinking that it is how the computer sees time. And it is the root cause of problems.

Our product currently runs in US and Viet Nam. US is primary base because our customers are American. Viet Nam bases are for customer services only and date time representations must be in US timezone. US itself streches across multiple timezones. We chose US/Pacific as the default timezone because our server is located over there.

Remind that each machine has its own timezone and the data conversion between machines are independent. Our need is showing date as the same no matter what timezone clients are in and showing at US/Pacific date time. If a user in US input a date as Dec 10 2020 08:00AM, a user in Viet Nam must see the time Dec 10 2020 08:00 too and vice versa, when a user in Viet Nam input Dec 10 2020 08:00, user in US must see Dec 10 2020 08:00 too.

Let say a user in VN inputs a date at Dec 10 2020, 00:00AM, the client application (we implement Single Page Application) converts this date to timestamp 1607533200000 then submits to the server. If the server stores this value, a user in US will see that date as Dec 09 2020 09:00:00.

→ To cure this, we decided to detect the client time zone and submit to server. So that, server application can adjust the timestamp to target timezone.

In fact, before storing to Datastore, we adjusted the timestamp to GTM+0 timezone. This is achieved by a few implicit logic that other colleages may unaware.

Example a user want to store Dec 10 2020, 00:00AM when he is at VN (GMT+7), it means Dec 10 2020, 00:00AM GMT+7, server tries to convert to date Dec 10 2020, 00:00AM GMT+0 which is T = 1607533200000 + 7 HOURS. Whenever a user want to get that date back, assume he is in timezone GMT+6, we adjust from stored timestamp : T’ = T – 6 HOURS.

This way, we can display the same date regardless timezone, in theory. This implicit logic is to hide the complexity for front-end works but, honestly with my feel, this is a crime because it does hurt developer brains and brings surprises.

Above method will work well unless there is another monster call DST (Daylight Saving Time). Actually contributing to this crime is the way we are getting client time zone. Practically, sending timezone along with each date field is seem noisy to developer at the first glance so we decided to get it using a HTTP Header named tz. This tz is calculated at the time the client application builds the request, this case it is using Date::getTimezoneOffset() of Javascript . So a bug happens when a user is outside of DST period select a date in DST period and vice versa. See below for an example :

  • Let say the DST period is from Mar 10 to Nov 10. Notice that this period is different between years. A HTTP request created at Feb 01 in US/Pacific will have a header tz = -8. This request need to carry along another date : May 10 00:00 . Because the Date instance of Javascript also automatically detects timezone itself, so, it knows that this May 10 is in DST period, so what it returns is May 10 00:00 GMT-7 timestamp instead of May 10 00:00 GMT-8. As the result, we submit the timestamp of May 10 00:00 GMT-8 which is equal to May 09 23:00 GMT-7. Then when it is toString() in client side, people see it is May 09 instead of May 10

Solution

To get rid all headache in storing Date field, processing/converting them, I introduce a new way to store Date data. In short, we stored date as a String with format :

yyyy-MM-dd’T’HH:mm–[timezone_id].

Example : 2020-12-10T00:00–US/Pacific. I call this DateString

Benefits : This way, we eliminate all parsing/converting code which is bugs’s favorite places, ensure the readability over data and keep data consistent. It is not hard to write functions to replace methods of java.util.Date by processing above date string.

To support this kind of Date, we created an input named DateInputWithTimezone which get & set value by String. Server side application there is nothing to do except storing submitted string. The timezone tail of this DateString allows to make timezone selector feature that allows users specify timezone the date they are inputing is at.

Query support : This date string format also support queries on date. If the date A is after date B, the DateString A also is “greater than” DateString B. Example to filter documents created from Mar 01, 2020 to May 01 2020, we can compare strings like :

bundle.find(...)
.where(Document.created, GREATER_THAN_OR_EQUAL, "2020-03-01T00:00--US/Pacific")
.where(Document.created, LESS_THAN_OR_EQUAL, "2020-05-01T00:00--US/Pacific")

Trade off : A potential problem is when a date field contains data in multiple timezones, example some document is at US/Pacific, some is at VN/Ho_chi_minh. There is 2 approaches to deal with these :

  • Make an converter to make sure every date strings are stored as 1 timezone
  • Use an additional timestamp field which is deduced directly from each DateString, store it beside DateString field and do query on that timestamp field.

An example of a input with timezone selector

Software developer pathways

Target audience : People with intent to be a software developer

Let’s skip the part of reasons and motivations that make you decide to be a developer, it’s maybe your interesting, or it’s just about money, or the life just pushes you to, etc , this post is to give you some guideline to go on this road.

Developers is likely heroes in games you play. What skill that hero should have, how to level up, which criteria to put points to after level up, which bosses to defeat and the most important thing is whether you understand the story behind the game you are playing, to enjoy it !

Let’s start with the story of developer

Software Developer world map

Developers, software developers is to create applications to solve real life problems to serve human need. Finding the need is a difficult task too and it deserves to discuss in another post.

There are many kind of applications. Names of application kinds depends on where it run and how it run. It is up to you to choose to follow one or many.

  • Desktop application : Applications that run on computer / laptop with UI for user to interact with
  • Web application : Applications that put in a server and you access by using web browsers. There is 2 parts of a Web application called Client side & Server side. Technology used in each side is different too.
  • Mobile application : Applications that run on mobile phones, now include Android & iOS
  • iOT application : Applications that run on multiple devices connected to each others in some network model

Imagine this is hero class selecting phase of the game you gonna play. Let thanks god because you don’t have to name your character :)). But each kind of application requires you to use appropriate tool sets.

There is another kind of define developer class when model client-server application model is dominant nowaday, it is :

  • Front-end developer : Is ones who take care of Graphical User Interface (GUI) for user to interact with. It includes Desktop Application, Mobile Application and the client side of Web Application
  • Back-end developer : Is ones who take care of something like system architecture, database, etc, things that are not visible to normal users.

To create any application, you are required to know

  • A programing language for your kind of application
  • A Integration Development Environment (IDE)
  • A framework or libraries for your kind of application
  • A database for your kind of application
  • A package management tool for your kind of application
  • Know how to deploy/release your kind of application
  • Know how to test your applications

Languages

Programing language is your weapon. It will determine which kind of application you can make. Below is the most popular languages at the moment of this post

  • Java : well-known as a cross platform language, Java can be used to create desktop application, server-side of web applications, Android applications
  • C# : for Desktop applications on Window
  • Javascript, HTML, CSS : This combo is essential for client-side of web application
  • Python : good for build tools but also good to build Web application
  • NodeJS : built upon Javascript, well-known for server-side of web application
  • Kotlin : well-known for Android development and as a replacement for Java in mobile world
  • Object-C, Swift : well-known for iOS development
  • PHP : well-known for decades in web application development

A lot of languages right ! Everyone wonders which is better than others. The answer is none. Each language has its own benefits and use cases that we will discuss later. And nowaday, it is very normal that a developer can use more than 1 language.

IDE

IDE is the software built for developers, to make their life easier when dealing with common problems while writing code:

  • Remember syntaxes
  • Remember boilerplate codes
  • Command lines
  • Compile code, debug & run
  • Setup environment
  • Search usages of a function or varible
  • Search a piece of code / text among a bunch of files in a project
  • Organize project
  • Format your code for readability
  • ….

The most of IDE provide features like code suggestion or auto complete to that help you type faster and more correct and more readable, to avoid most of typo mistakes. They also have excellent text searching feature that really helpful for troubleshooting problems with your code. Some advance IDEs even can suggest you what need to do and what to do next in what you are doing. And debugging support, this one will save you a lot of time – sometime you have no idea what you are writing, trust me :)), debugging is the only way to figure out. Below is the most advances IDEs currently :

  • IntelliJ : the best at my point of view, but it is not free. But you may find some crack somewhere :))
  • NetBean : Free, very equal to IntelliJ
  • Visual Studio : Free, most popular IDE, usually used in academic courses
  • Android Studio : Dedicated for Android developing
  • XCode : Dedicated for iOS developing

Learning to use a IDE may take time too but it is worthy. It helps you more efficient and look professional too.

Framework / Libraries

Language is weapon but know how to use weapon deadly is matter too. Imagine it is likely that why you need to learn kung-fu while you have arms & legs already. Framework is built by top level developers and it is embedded with programing experience in decades. It provides ready to use structural solutions in for very common programing problems , kinda of best practices. A little different from framework, Library is a set of tools that help you solve programing problems but not strict in a predefine structure like a framework, you are the one who are responsible for that structure. Below is some most popular nowaday framework/ libraries. The popularity here depends on the demand on job market : (the order is no meaning)

  • JavaFX : built from Java, for Desktop application
  • .NET : built from C# ,well-known good to build Desktop application, but it also can build Mobile Application, Web Application and iOT application too.
  • Spring : built from Java, for server-side of Web application
  • ExpressJS : built from NodeJS, for server-side of Web application
  • ReactJS, AngularJS, VueJS : built from Javascript, for client-side of Web application
  • Android Studio itself contains a framework to develop Android application
  • XCode itself contains a framework to develop iOS application
  • Laravel : built from PHP, for Web application
  • Django : built from Python, for Web application

Database

Database to store data. Depend on your purpose , it can be the most advanced storing technology or just simple files.

Below is some popular database technologies to learn about database for Web application:

  • SQL : Typical relational database.
    Relational database means it requires data to be stored in a structural way, with clear relationships between them. SQL offers a strong transactional query (that we will learn later) that ensure consistency of data.
    – SQL is a good candidate for applications that dignify the data consistency over other features ( like banking system, accounting system for example ).
  • MongoDB : Typical Non-relational database (NoSQL), easy to scale but requires extra setup effort.
    – MongoDB can be a great choice if you need scalability and caching for real-time analytics; however, it is not built for transactional data.
    – MongoDB is frequently used for mobile apps, content management, real-time analytics, and applications involving the Internet of Things. If you have a situation where you have no clear schema definition, MongoDB can be a good choice.
  • PostgreSQL : like SQL but more advanced with additional features.
  • Couchbase : NoSQL type, with Sync Gateway allowing to synchronize data between server and client side seamlessly. If you need an application with realtime data update, Couchbase can be a good choice
  • Cassandra : NoSQL type, support scaling out-of-the-box. If you need a database that is easy to setup and maintain regardless of how much your database grows, Cassandra can be a good option. If you work in an industry where you need rapid growth of your database, Cassandra offers easier rapid growth than MongoDB.

Databases for Web application are usually hosted in dedicated server for best performance to serve from hundreds to millions requests per minute

Different from Web application databases, Client side applications like Desktop application or Mobile application require more lightweight solutions to store data locally. Data that client side applications store usually are application settings, user preferences, static data, cache data from remote database (if it has a server side), etc

  • SQLite : SQL type
  • Realm : NoSQL type and faster than SQLite in common operations
  • Couchbase Lite : a counter part with Couchbase database in server side, with builtin sync features

Thanks to community , each language today has it own libraries to interact with databases. Unlike language, you should know more than 1 type of databases, at least 1 in SQL type and 1 in NoSQL type to feel different ways to solve a problem.

Package management tool

Building an application means solving a lot of problems. Thanks to community, the world of open source, most of problems are solved and packaged out there. When you build an application, you always need a few or a lot of them.

To manage the structure of the project and to bring more autonomous to application building process, each language usually has its own package manager tool(s) to :

  • Install/Update/Uninstall packages
  • Create a building cycle of the application for continuous development and integration
  • Manage project structure in consistent way but easy to expand too

Below is some Package management tools for each language :

  • For Java application : Maven
  • For Android application : Gradle
  • For Javascript application : NPM
  • For HTML & CSS : Bower
  • For PHP application : Composer
  • For Python application : pip
  • For C# : NuGet

Deploy/Release process

This is the critical phase of building an application. It is bring what you build to the real world, where people can access it, and use it. It depends on kind of application that we use term deploy or release. If you are building the server-side application, we use term deploy, because you are going to send your application to a server, to execute. And if you are building the client-side application , like Desktop app or Mobile app, we use term release.

  • Android & iOS applications have its own release processes that you can find in official documents of them. IDEs usually support application release process . Then you have to learn the process to uploading your applications to Play Store (for Android) and Apple store (for iOS)
  • Desktop application is easiest, the version you build while developing can be used as release version already. Your next work is to introduce it to your customer
  • Deployment process is more complicated. Because the server is mostly run on Linux OS nowaday, it is very recommended to learn how to operate a Linux OS, at least know how to connect to a remote Linux server via SSH & execute command lines when a tutorial asks you to do. More detail about Linux will be in another dedicated post. It depends on the language or the technology you choose that has a different deploy process. We will mention in another posts case by case.

Test your application

Last but not least, testing your application before delivering to the real world is an important phase that make sure you don’t disappointed people or lost customers.

The most basic technique of testing is manual test. Yes, you try your application in every cases and every ways can have to make sure it does not crash.

The more advanced technique is automation test, where you write code to simulate every use cases with your applications. This way is more professional, and more efficient, but also more skill to be required.

In automation test, there is a few sub kinds too. I name here only kinds I mostly use :

  • Unit test : is to test the correctness of functions or a set of functions.
  • Integration test : is to test the correctness in functioning of a group of components of your applications. In integration test, you have to simulate every actions in UI to interact with the application

To learn about automation test, below is some libraries for doing test in languages :

  • JUnit : Unit test library to test Java program
  • Chai & Mocha : Unit test library to test Javascript program
  • PHPUnit : Unit test to test PHP program
  • unittest : Unit test library to test Python program
  • Selenium : great tool to do integration test for Web application. It is a browser basically but controlled by developers
  • AutoIt, Appnium : great too to do integration test for Desktop application
  • Espresso : included in Android Studio, to do integration test for Android application
  • XCUITests : included in XCode, to fo integration test for iOS application

Wrap it up

You may concern that why iOT application is rarely mentioned in above lists. It is because iOT application includes many applications in many devices. Depends on what kind of device, you may choose yourself any tool above to develop. For example, You may have a phone to control electric circuit in your house, so you have to develop an Android application and a Java application on the device controlling the circuit, a Rasperri Pi for example.

To wrap it up, I note down below some popular skill sets currently for you upcoming hero to choose:

  • Web application in Java : Linux, Java, Servlet, Maven, JUnit, Selenium, ReactJS, HTML, CSS, PostgreSQL
  • Web application in Javascript : Linux, NodeJS, ExpressJS, NPM, Mocha, Chai, HTML, CSS, ReactJS, Selenium, MongoDB / Couchbase
  • Web application in PHP : Linux, PHP, Laravel, HTML, CSS, Javascript, PHPUnit, Selenium, SQL / PostgreSQL
  • Android application : Kotlin, Gradle, Expresso, Realm / Couchbase Lite
  • iOS application : Swift, XCUITest, Realm / Couchbase Lite

To proficient in any skillset is time consuming, it can take you years but don’t worry, most of companies don’t require you to master all of this before applying for a job unless you are applying for Senior position. Most of times, people master their skill via their job. So keep learning and learn in the right track