Step 5: stub server

The stubs we introduced previously are good enough, but there’s a serious drawback: the stubs that are only supposed to be used in development and end to end testing become a part of our production build, along with the ApiServiceStub – this is obviously less than ideal. A better solution is an external stub server: a tool we built to support our development that we also open sourced. It can be used as a global tool or a local dependency, it’s just an npm package. In laas, we install it as a local dev dependency with npm i --save-dev stub-server-with-ui. We make a few more additions in our package.json:

We also install concurrently as our dev dependency, so we can run both stub server and our app concurrently, at the same time.

The stubbed endpoints are defined in a simple json file stub-server.json:

Here, we define the 4 endpoints our app currently consumes: log-in, reset-password, get-own-user-record and get-user. For each endpoint, we specify an array of stubbed responses, each possible response is another json file with the actual response. For example, log-in-good.json:

This is arguably easier to reason about than stubs in the code we used before, and it’s a more clear documentation for inter-team cooperation – frontend and backend can quickly agree on shapes and fix them in stubs like this, and work in parallel from this point on, frontend app unaware of the where the data is coming from, it’s just a different API URL in the configuration. Default environment is local dev environment, see environment.default.ts:

By default, we are pointing to http://localhost:3333/api/, which is our stub server.

The stub server is used for local development as well as end to end tests. In local development environment, we can modify responses coming from each of the API endpoints via a simple web interface that looks like this:

Custom response is used to simulate errors – HTTP code of 500, for example. In the 2nd column, all recorded requests are shown, which is very helpful during development and is also quite useful in end to end tests, to make assertions about exact requests expected to be sent to the server.

The same manipulations can be performed programmatically in end to end tests via a simple API. Let’s look at our Forgot Password test in forgot-password.spec.ts:

In beforeEach we resetStubServer – this resets all stats accumulated for the endpoints; we are going to start all our tests with this.

In line 7, cySetStubEndpointResponse prepares the reset-password endpoint to return an HTTP error code 500, which is the default for non-file response (as indicated by isStubFile: false). Then we make assertions about submit button being disabled and validation working – this has nothing to do with the stub server as there’s no communication with the server, – the actual request is sent to the server once we click on btnSubmit in line 20. Since we set the endpoint to error out, we assert that we get a correct error message in line 21. Lines 22 to 24 are copy-pasted from the stub server UI. If you follow along with the steps in this test, or just run the test up to this point (by commenting out lines 22-33), and then simply open the stub server UI at http://localhost:3333/, you’ll see this same code in the bottom textarea:

This bottom part is made specifically for copy-pasting into end to end tests, it contains assertion code for the current state of the stub server: which endpoints have been requested, and with which parameters. By using this feature we can greatly simplify development of detailed end to end tests, and always be assured that we are not only testing the visual side effects (DOM elements on the page), but also the communication that happens behind the scenes – no extra requests are being sent to the server, and no requests are omitted.

In line 26 we use cySetStubEndpointResponse to set response for reset-password endpoint back to normal (stub file) with { isStubFile: true }. After entering a new email address and submitting the form again, we now assert that our URL has changed to /password-reset-email-sent, and that exactly one new request is sent to reset-password endpoint, with the parameters that reflect the newly entered email address.

We cover log in functionality with the same level of care and detail: every successful scenario as well as every error scenario is covered, see log-in.spec.ts:

The tests are fairly easy to read and maintain, let me know if you have any questions or suggestions!


Step 4: log in and reset password

The code at this point is deployed to

In this PR, we are adding multiple pages in app-routing.module.ts:

Let’s go page by page.

Log In page

We render a form with two inputs in log-in-page.component.html:

The logic is found in log-in-page.component.ts:

We are using Reactive Forms approach here, note how formGroup is constructured using, where we assign validators to each of our fields. emailField is extracted to MiscService to avoid copy-pasting as we are reusing this same field in ForgotPasswordPageComponent. Here’s what it looks like in misc.service.ts:

The error function is placed in MiscService as well – we’re showing errors when fields are touched and return human-readable strings (translated into other languages) based on which validator has failed, nice and clean. We don’t have to worry about change detection, because it happens automatically on user-generated events – which is exactly when we need to re-run validation.

We have a separate block for errors coming from the server, note errorFromServer element in the template. This gets populated from errorFromServer$ BehaviorSubject, which is set to 'wrong-credentials' or 'unknown-server-error' based on error field in the response. The response comes from apiService.logIn call, let’s take a look at how it’s defined in api.service.ts:

Every API request and response are strongly typed, the types are all defined in api.interface.ts:

All responses extend the base ApiResponse type, which only contains one field: error. This is our way of communicating when anything goes wrong on the backend – well, we don’t have any backend at this point, but that’s the plan, anyway. The error returned by the actual endpoint must be one of the enum values based on the request type – for example, for LogInApiResponse we define error as LogInApiResponseError, with just one possible value: WRONG_CREDENTIALS. This way the backend will always communicate problems to the frontend by a code (in this case, 1 means wrong credentials), and it’s up to the frontend to present the error to the user in a human-friendly way – we just show a string in selected language, but it could be a picture or even a video, the backend doesn’t have to worry about the presentation.

This way we treat all “good” errors, but there are also “bad” errors, like server is down, or unreachable, when response comes back with HTTP response code of 500, or 404 or something like that. This is handled globally using Angular HTTP interceptor mechanism, see http-errors-interceptor.service.ts:

What this does it catches exceptions with catchError and convert that into a generic ApiResponse with the field error set to HTTP status code from the error object. This way the form component can treat all errors in the same way, and just produce a different human-readable string based on the code.

The interceptor is installed globally in app.module.ts:

But how does it even work, we don’t have the backend yet? Here, we stub the ApiService with ApiStubService based on environment variable, check out this block in app.module.ts:

So every time ApiService is injected into a controller, the actual component gets an instance of ApiStubService instead of the real ApiService if isStub is truthy in the environment. And it sure is by default, see environment.default.ts:

A-ha! So when we “send an API request” from our form with this.apiService.logIn call, this actually goes to a stub method in api-stub.service.ts:

This way we can build our functionality on the frontend completely independently from the backend – in fact, we don’t need any server at all at this point and can focus on our UI. We can even cover all the scenarios with end to end tests, see log-in.spec.ts:

Quite a few scenarios we cover here! We even handle logged in state carry-over with cookies, log out and restricted access to some pages based on access level.

The cookie is set with this.authService.logIn(response) call, see auth.service.ts:

We set AUTH_TOKEN cookie on logIn, and clear it out on logOut.

Based on this cookie, we know whether or not the user is logged in, and can load user’s information upon app initialization, see how we’re requesting apiService.getOwnUserRecord() in init() – we need to know this before we render our header, and we also need to restrict access to certain pages based on logged in status. Sounds familiar? We had to do something similar with languages – before we render, we need to know which language we’re rendering for, and load the corresponding translation file. This is done at APP_INITIALIZER stage, in app-initializer.service.ts:

AppInitializerService will now wait for both languageService and authService to initialize before the app is considered bootstrapped and ready to render.

Access to restricted pages is handled globally in can-activate-guard.service.ts:

This guard will redirect to log in page if an anonymous (not logged in) user tries to access a page that is only allowed for logged in users, and it will also redirect to home page if logged in user opens a page meant for not logged in users – such as log in page, or reset password page, a user who is already logged in has no business going there.

The information about access restrictions is found in page.enum.ts:

The guard and route data are attached in app-routing.module.ts:

This is it, DRY and elegant – it will be trivially easy to add more restricted pages, as well as more complex restriction rules (such as “admin only”, for example).

We use the same form for both logging in and registering new users – if the email is not yet registered, a new user account is created and an activation email is sent. We then redirect to /activation-email-sent URL handled by activation-email-sent-page.component.ts:

This renders the cute envelope animation with a message to the user asking them to check their email and click the link with activation code. The envelope is rendered by EmailSentComponent, see email-sent.component.html:

The animation is triggered with a short 100ms delay by isShowEmail$ Observable in email-sent.component.ts:

Forgot Password page

Forgot Password form is very similar to Log In form, but even simpler, just 1 field; see forgot-password-page.component.html:

Just like with Log In form, we have the input, the errors block and the submit button. Note that we use autofocus attribute to automatically focus first input of each form – this saves our users a click, and we care.

The component in forgot-password-page.component.ts will also look familiar:

Here we’re leveraging apiService.resetPassword endpoint, which doesn’t define any custom error codes, so if anything goes wrong, we’re setting errorFromServer$ to 'unknown-server-error' – which is translated into English in en.json:

Note that we’re only using this file for longer strings or ambiguous situations (like with “Log In”, which is translated differently for the button and for the header, that’s why we give it a unique code here) – most of the strings are found in plain English throughout the code, but all of them are translated in ru.json.

Both happy path and error handling are covered with an end to end test in forgot-password.spec.ts:

User Profile page

User Profile page is shown at /:email route – we have just a dummy placeholder at this point found in user-profile-page.component.html:

We redirect to this page upon successful log in, but this page can be served for any user based on the email in the route. userDisplayName$ is the only dynamic thing on this page for now, and it is driven by the component found in user-profile-page.component.ts:

User data is populated from the, where it is attached by the route resolver found in user-resolver.service.ts:

If current user is logged in and is looking at own profile page, we’re just returning logged in user data with of(user). Otherwise, it’s someone else, and we need to load their profile from apiService.getUser.

Settings page

One last page we add in this PR is Settings page – it’s an dummy page that was added with a single purpose, to test restricted access. Access to Settings is only allowed to logged in users and this is tested in an end to end test in log-in.spec.ts.

We will look at the end to end tests in more details in the next tutorial, this one is already too heavy probably… oh well, I hope you enjoyed it and found it useful. Let me know what you think!


Fix for Markdown rendering for SSR

There’s a problem with ngx-markdown package – it doesn’t work out of the box with server side rendering, because the loader uses HttpClient to load the markdown from a file, but on the server side the relative path makes no sense (as there’s no base URL), so it actually fails to render on the server. Here’s the fix:

We provide a custom loader on the server side in app.server.module.ts:

This loader just reads the file with readFileSync on the server. Problem solved!


Bonus step 3.5: routing animations

Let’s have a little fun with animations:

We are going to add an animation on every route change. To do that, we attach an animation to the router-outlet wrapper in app.component.html:

We are introducing a new observable in MiscService called page$ – it will emit every time the page changes. This is what it looks like in misc.service.ts:

We define Page as an enum in page.enum.ts:

The values are relative URLs, that’s why we can simply do this.router.routerState.snapshot.url.slice(1) as Page conversion.

That’s all we need to trigger the animation: when page changes, we have a new value emitted by the observable. The same approach works for any sort of animation – as long as we have an observable, we can use it to trigger an Angular animation. The animation itself is defined in app.component.ts:

The cool thing about Angular animations is that we have access to both “previous” and “next” page – so when user switches from Terms of Use to Privacy Policy, we can access the previous page (Terms of Use) with :leave selector and the next page (Privacy Policy) with :enter query. We can even group the two animations together by using group. We could have different animations depending which page is the “previous” and which page is the “next” one, but we are going to have the same animation for all transitions; this is defined in transition: '* => *'means “from any value to any value”.

We have 3 instructions grouped together, let’s dissect them one by one.

First instruction is the initial state for the new page:

We are setting the new page to be outside of the visible area on the right with translateX(100%), give it a little rotation with rotate3d(1, 1, 1, -15deg) and scale it 150% with scale(1.5). We also set the opacity to 50% so the new page will fly in from the right, while scaling down to normal size, rotating and becoming opaque. The option optional: true is necessary because :enter query will only work when pages are changed and would fail on initial page rendering.

The second instruction is for the old page to fly away:

This goes in 2 steps defined in the array: first step to set style to { position: 'absolute', 'z-index': -1 } – we need this so the old page does not affect the layout. Without this step, the new page renders underneath the old one, because both exist at the time of transition, and that doesn’t look good at all. We set z-index to -1 because we want the old page to appear underneath the new one. The second instruction is to fly the old page to the left while rotating it and scaling it down.

And then finally, we reset styles for our new page with the 3rd instruction:

Here’s how this looks like when we increase the animation times by 3 seconds:

And here’s what it looks like with short animation times:

Pretty cool, right? 🙂

We also add ngx-markdown npm package in this PR to render pages Privacy Policy and Terms of Service – the markdown is generated by the lovely tool Privacy Policy Generator. The home page is just custom HTML, both in English and Russian – please check it out, hopefully the purpose of LaaS becomes more clear now.

Step 3: i18n, multi-lingual support

Fun fact: i18n stands for internationalization and can you guess what 18 means? Hint: it’s the same meaning as 11 has in a11y.

We are going to support English, because everybody speaks it, and Russian, because I speak it. Let’s dive in: (deployed to

We’ll need to render pages in correct language in SSR based on a cookie, so we make some changes to support cookies server-side in server.ts:

Just following instructions from @ngx-utils/cookies npm package here. What this does is it attaches parsed cookies to the request object by using cookie-parser and then injects both request and response Express objects to Angular DI container, so the cookies can be used in the app during server side rendering.

There are a few changes app.module.ts to enable multi-lingual support in the app:

Here, we add preboot – a neat npm module that helps with transition between server side rendered HTML and fully bootstrapped app – it’s a nice addition to any app with SSR (should have been part of the previous PR, but oh well). Once server side rendered HTML is delivered to the user, the browser will display the page and then begin bootstrapping the SPA code. So there’s a period of time when user can interact with the HTML already, but our Javascript is not bootstrapped yet, so we will lose these user interactions and leave the user frustrated. Preboot solves this problem by buffering the interactions and then replaying them once the app is ready to process user-initiated events.

For internationalization we are using ngx-translate – it’s a much easier solution than the one explained in the official Angular docs; the official one doesn’t actually support Russian correctly – there’s no ru-RU locale for example (USA sanctions?), and the other ru-* locales didn’t work for me. On the other hand, ngx-translate is very simple and free of problems. On the browser side, we are using TranslateHttpLoader to load translation files over HTTP, note how TranslateModule is bootstrapped for DI. We want to preload the translation before the app is considered bootstrapped – Angular provides APP_INITIALIZER mechanism just for that and we are going to add appInitializerService.init()to the bootstrapping process: the function provided for useFactory just needs to return a Promise so Angular can wait until that’s resolved before the app is considered bootstrapped.

On the server side, TranslateModule is bootstrapped in app.server.module.ts:

TranslateServerLoader is a simple service to load translation by language from the file system on the server side, it’s defined in translate.server.loader.ts:

The actual translation is performed by translate pipe; here’s how it looks like in footer.component.html:

If you pull this branch (git checkout 03-multilingual) and npm start, you can see how this works in your browser at http://localhost:4200/:

We can also validate that server side rendering reflects selected language by parsing the cookies; to do that, run with SSR (npm run build:ssr && npm run serve:ssr and open http://localhost:4000), select Russian language in the dropdown, then refresh the page and view source, you’ll notice that page is rendered correctly, with the Russian translations:

Log In button in the header.component.html is translated the same way:

All language-related functionality is encapsulated in language.service.ts:

Here, we expose the currentLanguage$ observable, init() method returns a Promise used in APP_INITIALIZER bootstrapping process, and setCurrentLanguage is used to switch language (when user makes a selection in the footer dropdown). We also deal with cookies here. Note how language will default to translateService.getBrowserLang() if no cookie is set.

Translation files are found under apps/frontend/src/assets/i18n/. English “translation” in en.json is actually an empty object at this point:

The reason this object is empty is that when translation key is not found, it’s used as is, so we don’t have to translate “Blog” for example (to English that is), as it’s the key for other languages and can be used as is. When we need to translate bigger blocks of text, we can give them names – same idea as variable names, – and then provide “translation” from the variable name (key) to English as well as other languages.

Russian translations are found in ru.json:

Even though we only deal with one cookie at this point, we’re introducing enum Cookie with a single key – it’s always a good idea to list things like cookies in an enum, so that we can quickly see which cookies we work with by looking at the file cookie.enum.ts:

For the languages, we extend language.enum.ts with language names – these are never translated and are used in the footer as is, each language name specified both in English and in the native language to make sure the users are never confused:

I hope you enjoyed this tutorial, and found it helpful. We’re getting ready for world domination, so i18n is a must. And, oh! – btw, – 18 stands for the number of omitted characters in the word internationalization (same as 11 stands for the number of skipped letters in accessibility) 🙂


Step 2: SSR, Server-Side Rendering

Our second PR adds SSR: (deployed to

SSR is pretty much obligatory for any SPA (single page application) – without the Server-Side Rendering, the search engines don’t see your app content, only an empty shell. If you checkout the first branch 01-initial-setup, run npm start and then open page source in your browser, you should see this:

This is not search engine friendly as it doesn’t contain any searchable text, only code. The text will get rendered by Javascript as the app bootstraps – this is good enough for our users, but not good enough for web crawling bots. This problem is fixed with SSR. Switch to 02-ssr branch, run npm run build:ssr, then npm run serve:ssr and you should see fully rendered HTML with all the text, so it can be crawled and indexed by Google and other search engines. We don’t have much text on the home page, but you can search for it to validate this is true:

This is achieved by adding Angular Universal – please refer to the official tutorial, it’s pretty good. Universal basically adds a new build target in angular.json:

This new target builds the app for the server. The app is then served by a simple Express app found in the server.ts – this code is created automatically by installing Universal. Things we need to do manually are very few.

We also added a cute little “beta” sign to header.component.html:

There’s not much else in this PR, it’s mostly auto-generated code. We also renamed LoginService to AuthService here and introduced npm run tests command that runs in sequence all linting, then all unit tests with Jest and then all end to end tests with Cypress – we don’t have a lot of tests yet, but they all pass 🙂

Coming up next: multi-lingual support.


Step 1: Initial Setup

We begin here, with our first PR:

To follow along, run these commands one by one:

Then open http://localhost:4200/ in your browser, you should see this:

The app doesn’t do much at this point, but there are quite a few things we bootstrap here.

First of all, it’s an Nx monorepo already, with a single Angular 7 app called “frontend” inside. Nx is great, it allows us to develop both frontend and backend in a single repository, which allows for easy typing information and functionality sharing. It also helps us to set up Jest and Cypress, and has a few more “Angular CLI power-ups” to improve development experience.

We add Prettier right away in our initial setup, because prettier is just so good. No need to worry about individual code style preferences, no holywars around spaces and brackets. The bigger the team, the more benefit you get from using Prettier. We customize it just a bit in .prettierrc, otherwise it’s just the default configuration:

We add a few routes in app-routing.module.ts:

Note how we are using an enum for Page – it’s always helpful for readability to make enums where a fixed set of pre-defined values needs to be handled. We start with only 3 pages: Home (default), Privacy Policy and Terms Of Service – this is a fixed set of pre-defined values, so a perfect candidate for an enum. It’s a great imrovement over a free-form string, because it provides type safety and documentation – by simply looking at the enum, we know what pages we have in the app, this way we are building our DSL, domain-specific language.

Page enum values are relative page urls – by encapsulating this information in the enum we are also following the DRY principle – arguably, the most important principle of software development. If we want to change the url in the future, we won’t have to touch multiple files, the actual url is only found in a single place, right here in page.enum.ts:

We are building a Bitcoin app, Bitcoin is borderless, so we will need multi-lingual support. We add a dropdown for language selection in our footer.component.html:

It’s a fake right now, but we will implement this soon in an upcoming Pull Request. Note that we are using Material Design in this project, it’s a natural choice for an Angular app that works great on mobile as well as the web.

There’s a bit of interactivity already going on in the header:

This is again a fake, but not a complete fake: we introduce LoginService that exposes login and logout methods as well as Observable user$. Note how all of our components use ChangeDetectionStrategy.OnPush – there’s no reason to use default change detection strategy, using observables with async pipe is straightforward, and not using it is very expensive in terms of app performance, plus it’s harder to reason about. When everything is streamed asynchronously via observables, things are simple and fast. Here’s what LoginService looks like:

This is a nice little pattern we’re gonna use a lot – a service that exposes observables and methods to manipulate the observables. The view components consume the observables by using async pipe. The actual state is encapsulated in the service with a private BehaviorSubject, exposed publicly using _privateSubject.asObservable(). This pattern is called a Facade (when describing public API), and a Service with a Subject (when describing the internal implementation). Using NgRx is not an improvement over Service with a Subject in my experience, as it leads to more complex code that is harder to maintain and extend – but, by using Facade we can switch to using NgRx without having to modify any of the components, because from the point of view of the components, they will still consume the same API: call a method to affect the state and just subscribe to observables to get state changes streamed to you. The inside of the service can dispatch an action and expose an observable made from selectors if you choose to use NgRx, it wouldn’t matter on the outside, the public API of the Facade stays the same.

Here’s another place where we’re using this pattern – MiscService:

We are using Angular flex-layout here to expose isMobile$ observable – as user changes window size, we’re going to stream true or false through this observable to indicate whether or not we’re on mobile phone sized screen. This is going to be useful for responsive design. Note how header layout changes for different page width:

This is enabled by isMobile$ observable in header.component.html:

We also introduce shared library, with a couple enums and interfaces, for example User interface in user.interface.ts:


We have set up a monorepo created with Nx, with a single Angular 7 app, one shared library, basic routing, responsive design based on Angular flex-layout and a fake login service to simulate authentication state. We set some code quality standards by installing Prettier, setting up TSLint and insisting on ChangeDetectionStrategy.OnPush. We are getting ready for multi-lingual support, for unit testing with Jest and end to end testing with Cypress. It’s all broad strokes just now, but the outline of the project hopefully begins to emerge.

Reach out to me with any questions and suggestions: @ALeschinsky on Twitter is probably the best way to contact me.


Show me how you move

This blog is going to be very opinionated. I’ve been writing software professionally for almost 30 years now, and before that I was competing on a global level as a school kid (representing Ukraine in a World Olympiad in Informatics back in 1993), so I have a lot of wisdom to share (and not too much modesty), so welcome if you want to learn.

Before we get to LaaS code, I wanted to talk about moving through the code. This aspect is easy to overlook and I don’t see a lot of articles about it anywhere, which is a shame. Programming is similar to video games in a way – you have a map of the world in your mind, you remember where everything’s at, and to be efficient you have to be able to move around with ease. Ideally with grace even, with no unnecessary efforts, very quickly and without stumbling. Look how professional Starcraft player fingers dance on the keyboard:

When playing to win, you don’t have time to think about where the individual fingers go, you need to think about resources, armies, your long-term strategy – the fingers just do the work following your intentions, subconsciously.

For software engineering, the first step in terms of moving gracefully is of course to touch type – if you have to look down to find the keys with your eyes, do yourself a favour and learn to type without looking ASAP. Human brain has a limited capacity, and if you’re thinking about individual keys you are not thinking about program architecture, algorithm branches, edge cases and other things you could be thinking about – those brain “CPU cycles” are wasted.

Pretty much everyone touch types nowadays, which is great. But there are at least 2 more techniques that are just as crucial for being productive as touch typing – only contrary to touch typing I see most of programmers not using them. It’s like watching someone play Doom for the first time – instead of having fun and killing demons they’ll just bump into walls helplessly.

Go to Declaration and Back

First of these 2 techniques is simply going back. Most programmers use “Go to declaration” feature already – it’s just too good, even the beginners use it. But it only gives you a fraction of value if you don’t have a shortcut to go back. Sometimes I just can’t help but notice how people literally look lost after “going in” (e.g. going to declaration) a couple of times, and have to use editor tabs, or global search, or look for the file in the project directory tree to return… and if it’s the same file, they scroll… such a waste of time and focus! This in turn makes you afraid to go to declaration often, because getting lost sucks.

But it’s a problem that’s very easy to fix: just go back by using “Back” feature (duh!). It’s incredible how underused this feature is. Assign a shortcut to it that you like (I use Ctrl+Backspace), and use it all the time. Never go back by searching or clicking around – the previous location is always one keystroke away. In Webstorm, go to Settings, Keymap and search for Back to assign a custom hot key:

This changes the workflow. You see a function that you don’t quite remember what it’s doing? Ctrl+click it – or better yet, press your keyboard shortcut to go in (keyboard is way more efficient than mouse or god forbid touch pad), – take a look, and go back with Ctrl+Backspace or whatever your preferred key combination is. It takes a second, and you don’t lose your train of thought this way. Since it’s so cheap to do, you can jump to declaration multiple times in a row – you see that function, and there’s another function, and then there’s an interface you don’t quite remember what the shape of it is – just go in the second, the third time, take a look, and come back quickly to where you started. No mental effort required, the fingers just follow your intention and you don’t lose your train of thought.

This is so simple, and such a great boost to productivity, I really cannot emphasise this enough. By doing this all the time while developing, you get to know the code in a very different manner, it becomes like a big hyper-linked web of things, you start to feel how the project is made of interconnected objects and pathways between them. Very much like in a video game, you build a mind map of the world you’re in – and you move through it gracefully, without giving a second thought to the mechanics of fingering. And if you don’t feel the game, you’re gonna lose to someone who does every single time, they will just run circles around you.


This technique serves the same purpose as going to declaration and back: to prevent getting lost in the code. When working on a piece of code for a long time, just bookmark it with Ctrl+1 – this way it’s always just one keystroke away. See a method and want to jump through the usages? Just press your shortcut for Find Usages, scroll through the list with Next occurrence and Previous occurrence (obviously, using keyboard shortcuts), and wander around the code with ease and confidence – the piece you’re working on at the moment is always just one keystroke away, so you are never really lost.

Bookmarks remind me of Starcraft groups a lot – not only the actual hot keys are the same (Ctrl + number), but the feeling of control it gives you is very similar. In Starcraft, you have multiple groups within your army that you can switch between and control independently, and in programming, you have multiple pieces of code you’re focusing on at the same time. It could be, for instance, a unit test and the code under test (I use Ctrl+0 for the test I’m currently working on, and Ctrl+1 for the code under test), or controller and template, or one main function and a couple auxiliary functions, or a service and interface definitions and some dependencies – there are up to 10 bookmarks you can have, which is more than I personally can handle, I don’t really use more than 3. But I pretty much always have at least one bookmark – being able to quickly go back and switch between 2-3 places in the code is just invaluable in my opinion.


There are more important techniques, of course, but these 2 – Go to Declaration and Back and Bookmarks, – I find to be the most undervalued and underused. If you’re not using these IDE features yet, give them a try, I guarantee you will increase productivity this way (be a happier developer and make more money, yeah?) Good luck, reach out to me with questions and suggestions; feedback is always appreciated – and stay tuned for more good stuff soon 🙂

LaaS: Lightning as a Service

We are finally ready to announce the project we have been working on for the last year!

It’s a fully Open-Source project, but it’s also a for-profit business, with a team of paid professionals working on the code. Our goal is to build a thriving community around it, and hopefully make some money as well, sort of like WordPress, MySQL and many other successful Open Source projects do.

The project is called LaaS and it’s going to live at There’s nothing there just yet, but we have most of the code developed by now. Next step is we are going to start releasing it in a series of step by step tutorials on how we built it from scratch – this way it’s also going to grow into a free educational resource on Angular, Nx, Docker, btcd+lnd,, jest, cypress and more. We’re going to really polish it out, spend time on things like multi-lingual support, 100% unit test coverage, thorough end to end tests. Bitcoin is cool and different, and we are also trying something cool and different here – it’s not a standard business model, it’s an investment into the future, into the community, at least that’s what we’re aiming at.

The name LaaS is a play on words: there are SaaS, PaaS and IaaS – Software as a Service, Platform as a Service and Infrastructure as a Service, – and now there’s LaaS – Lightning as a Service. It’s a service for people who don’t want to run a full Bitcoin node and a Lightning Network node, manage channels, worry about incoming and outgoing liquidity, backups – they can just use Lightning as a Service, via the UI or the API. The .sh domain suits us perfectly: looks like a name of an executable Linux shell script, which is really cute, we’re really happy with it.

LaaS is a monorepo built with modern frameworks and tools, see our on GitHub for more details. It consists of two parts:

The first part is the API: it’s a backend application built on top of a dockerized stack that includes btcd, lnd, PostgreSQL and ELK Stack. We will publish detailed step by step installation instructions for everything you need to run LaaS API as a self hosted service for your own projects on your own servers and dev laptops. You can just use it yourself or resell it and charge your users a fee, it’s fully yours if you are running it, you can modify it as you like (we hope you’ll submit a Pull Request if it’s something useful for the others in the community, deal?), we’re releasing everything under the MIT License. There will be tutorials and (probably) video lessons on how to set up enterprise grade deployment pipeline on bare metal from scratch, with GitLab running tests and deploying into different environments, with Portainer giving you access to all your containers, with logs in Kibana, with automatic backups and monitoring tools.

Bitcoin is all about low time preference (if you don’t understand what that means, please read The Bitcoin Standard immediately! I’ll wait) – so prepare for a long ride. Although we have most of the code developed by now, we want to really polish it out before open-sourcing it on GitHub. We have very strict due dates in our roadmap; it’s actually the same due date on all of the milestones: once it’s ready. We are actually going to open-source the API last, we’ll start with the second part first:

The second part is the app: it’s a simple hosted Bitcoin wallet where registered users can receive and send Bitcoin, on-chain or via Lightning Network. There is a QR-code scanner, a simple report on transactions, a PWA with push notifications for mobile and tablets, all the essentials that every Bitcoin-based project needs. We want you to build on top of it – come up with ideas, build cool things, go nuts! Use LaaS as a starting point – just clone it from GitHub and you are ready to work on your features in minutes.

As we build our app in a series of tutorials, each step is going to be pushed to <step#> branch in git and deployed to https://<step#> For example, the first URL will look like The latest step will also be found in master branch and deployed to Once we’re done building out everything with stubs, we will connect the app to LaaS API exposed at – the API is not going to be open-sourced at this point yet, but it will be made available to everyone via the app. Every registered user gets a hosted wallet, and also an API key. It’s going to be a paid API, and that’s how we’re going to make money – hopefully it’s gonna be enough to cover the web hosting, but if everything goes according to the plan, it will cover our lambos as well (evil laughter). Once this is done, we have a working business, with the app part fully open-sourced. The final milestone is open-sourcing the API part, which we will approach in the same manner, as a series of tutorials where we share the lessons learned during the first year of development.

It’s just a roadmap at the moment, but we are pretty much production ready, so stay tuned for regular updates. Please do contact me with any questions, suggestions and offers to help, I’m @ALeschinsky on Twitter. You’ll meet the other team members on GitHub, most of the blogging here I’ll probably do myself. One area we’d love immediate help with is translation to other languages – we are going to start with English and Russian, please reach out to me if you want to help translating LaaS into your language. Bitcoin is borderless, Open Source Software is borderless, and LaaS aspires to be borderless as well, so all languages are welcome.

Wish us luck! 🙂