I love the concept of 'anything can be log'

A while ago I read this (chinese) article talking about how people build complicated architecture with log approach, back to then I didn’t quite get it, but it did scratched something - something I am really longing with. A insight for better software architecture.

The article mentions that log is used in almost everywhere, because log has the following features:

Timestamp - a log has timestamp describing when happens what.

Sequence - since every log has a timestamp, we can line it up, make it an array. In that way you can see a timeline of events describing what happens in a system.

Describing Actions - instead of really executing something, log just describes what is going to do.

Log has been used in many domains like version control, database, replication, event stream and many other aspects for solving complicated problems.

Imagine we have a database, and it is writing something into disk, and suddenly computer crashed. Here comes the problem - how do we restore database to the point before crash and let it continue its job?

The answer is log, it writes log first, and then, really executing the action. Since we have a log that describing the system state, we can resume the state and make it continue its job.

Log can even be used in replication as well. Syncing data among all machines/process is not an easy thing. How do you keep data on all machines identical while sharing? Move physical data? That would be inefficient because physical data is large and plus network bandwidth issue. How about sending log instead? Log is relatively small and actually its just an history of state, instead of sending physical data, we send a series actions that should be carried out, and by following the same trial, state should be the same in the end.

And what’s the point when it comes to front-end? Today’s front-end is way more interactive than 15 years ago. Lots of actions and events come and go in our application. Trendy developers probably have heard Redux - a central event management implementation for resolving complicated events.

One of a reason that really makes Redux great is, yes, log. In Redux we deliver log first, and delay the action (side effect / mutation) afterward.

1
2
3
4
5
6
7
8
9
10
11
12
13
const fetchDataLoadingAction = () => {
type: "FETCH_DATA_LOADING"
};

const fetchDataDonesAction = (data) => {
type: "FETCH_DATA_DONE",
payload: data
};

const fetchDataFailAction = (err) => {
type: "FETCH_DATA_FAIL",
payload: err
};

Despite there are Action in those names (a common naming convention for redux), those are actually logs describing an action, and if we want to execute an action, we can wrap it in a function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

// here we use redux-thunk for handling simple async or combining serious of actions together.
const fetchData = () => (dispatch) => {
dispatch(fetchDataLoadingAction());
fetchDataAjax()
.then(data => dispatch(fetchDataDoneAction(data)))
.catch(err => dispatch(fetchDataFailAction(err)));
};

// keeping new state in our reducer
const INIT_STATE = {
fetchState: "",
data: {}
};
const reducer = (state = INIT_STATE, action) => {
switch(action.type){
case "FETCH_DATA_LOADING": {
return {...state, fetchState: "loading"};
}
case "FETCH_DATA_DONE": {
return {fetchState: "success", data: action.payload};
}
case "FETCH_DATA_FAIL": {
return {fetchState: "fail", data: action.payload};
}
default: return state;
}
};

// later...
store.dispatch(fetchData());

// if you have installed redux-logger you will see something similar to this
// action: { type: "FETCH_DATA_LOADING" }
// state: { fetchState: "loading", data: {} }
// ...
// action: { type: "FETCH_DATA_DONE", payload: "foobar" }
// state: { fetchState: "success", data: "foobar" }

By using log, developers can manipulate the timeline of an application, performing actions like undo and redo or jump to a specific time of state for debugging. This is the beauty of log.

Introduction to Progressive Web App (PWA)

What is that?

Buzz word time! Progressive Web App (will be written as PWA in the following post), promoted by Google, basically means delivering user an app-like web app. It concludes the following features:

  • Responsive - available on many devices: desktop, phone and tablet.
  • Reliable - accessible even if the network is down.
  • Fresh - always up-to-date, updating without getting through app store.
  • Safe - can only be accessed via HTTPS.
  • Discoverable - unlike native app, since it’s an web app, content should be discoverable by the search engines.
  • Engaging - PWA can be access like an native app. You can access them by adding them to home screen, and provide them an seamless full screen experience.

but that sounds very…unclear. We want to know how it was made right. Here is the heart of Progressive Web App:

  • Service Worker - the first pillar of PWA. It’s an API that hijacks networking request, and responds browser with additional messages.
  • Cache Storage - the second pillar of PWA. A member of Web Storage. An API developer often use with Service Worker. It caches request as key and responds with cached value if corresponding key is found.
  • Web App Manifest - a JSON-based manifest file provides ability to set things like app icon name or display mode and many other things.

Platform support

service worker API on MDN

In the current status, service worker is not available on iOS, which says your app still can’t benefit from PWA, but the good news is even if the working environment hasn’t support yet, your app will fallback to the traditional caching strategy. Your app still works without modifying codes!

PWA vs Native

PWA is an improvement to the web and user experience, making it more like an native app, but that doesn’t mean it’s going to replace native app or against native app on par.

PWA is just a collection of features and it’s not a platform like native. A fair fight should be “browser vs native”.

If you take a look at what web can do, you might think “cool I can finally develop something like native does on mobile!” However the current compatibility on iOS still has long way to go, if you take a look on those API closely, you will find out most of them only available on Chrome on Android.

How does it work?

Please check pwa-test written by me. It’s a simplified version of Your Frist Progressive Web App.

I don’t want to write every step down here, because, first, I am lazy, and more important, I think Your Frist Progressive Web App has done a great job on tutoring. I believe it already provides all the details you need.

However there are still some pitfalls when developing with service worker, in order to save your time, here you go.

Higher level API

After read all the tutorials, you found you have to write many codes to achieve PWA, but… you are a lazy programmer like me, and wondering “where’s the higher level API candy?” Well, people heard you. Here comes some candies!

  • sw-toolbox - a collection of service worker tools to help developing offline web app.
  • sw-precache - a helper for integrating service worker with building chain like gulp.
  • webpack-offline-plugin - a webpack plugin for building offline web app.

References