Traversing Deno Land - Building a URL Shortener
Being a fan of JavaScript (before the Web 2.0 days), I have followed most trends in this language both in the client side as well as the server side. JS has matured leaps and bounds. And I have been amazed and surprised by how JS has found its cozy corner as a suitable competitor in the server space. (Rhino, NodeJS, IOJS and now Deno).
So it was a natural urge for me to delve into Deno. And what better way than to get my hands dirty by building a project. I had previously built a URL shortener in NodeJS, and reading a recent post about somebody who was attempting to build one with NodeJS, inspired me to build one in Deno. I did not want to use it in production yet, but wanted to see how tough the journey is to get it there.
Starting the journey was simple, Deno.Land (yes, that is their home. creative :) ) has a very good explanation on how to start up. Installation was simple. And I tried out the customary hello world (in this case a server response) to assert the simplicity. Was running in less than 5 minutes.
To build the URL Shortener i needed multiple components such as :
- HTTP Body Parser
- HTTP Route Handler
- DB retrieval framework
- Short id generation framework.
It was a struggle searching for framework to accomplish the above. Why - deno.land has a list of all the 3rd party components as well as their standard libraries. BUT - standard libraries are not grouped. So unless you know exactly what you need, it is difficult to find. Maybe there was some intrinsic knowledge which is expected which I did not have. But i believe documentation would have been easier if they were grouped into packages. Example 1 - I struggled to convert the HTTP byte stream to the text string. I kept searching for an UTF8 encoding/decoding in the std libraries. It took some effort to realize that what I needed was a TextDecoder. Example 2 - Go to their docs and find the way of deleting a file. You would get a hint if i told you to remove the file instead.
The number of modules available in 3rd party section is limited, but i am seeing many packages quickly building compatibility to deno. Example - the ShortId package i used is also found on npmjs and the compatibility to deno was already present.
Finding a package / module is tough. And I missed npmjs' ratings and "number of downloads". But that was until i realized that we could include npm packages by following the steps in the URL rewriting service for npm found under /x of deno.land. (link)
These abover were small hurdles and I managed to get over those with a little bit of effort. I used Visual Studio Code for building the application, and it has enough good plugins to ensure that syntactical errors are highlighted. I missed nodemon, but i believe nodemon can be easily customized for other command lines (https://github.com/remy/nodemon#running-non-node-scripts). I did not try it, though.
Deno has benefitted a lot from using TypeScript. After building and productionizing a LARGE application on NodeJS application, i understand the importance of needing static typing in larger applications. And i see the clarity of thought coming from the code that i was writing. The initial code was crappy, as i had basic experience in writing TS. But i was very easily able to abstract and add structure the functionalities into classes. I did not do it a 100%, but I stopped when i realized it was easy to get there.
Finally it was time to push it to a linode server. As I rely my faith on dockers, i searched around for a docker image and realized there was no official docker image to host the deno code. I did not try the unofficial images, but i did attempt to build a Docker of my own with alpine. Thought it would be simple, but it did not work. Maybe I will try it again some other time. And probably it will be sometime before a "certified" Docker image will be released.
I did not do any perf test to compare the speed of response or the number of requests handled per minute (RPM) as I dont believe Deno has that goal. Maybe i could have evaluated the startup time, considering i was using TypeScript versus JavaScript, but i did not try it out.
Finally
***** DrumRoll *****
https://github.com/psachinnayak/deno-url-shortener
It was up and running. I played with it a bit. and after i was satisfied that i had built a world class application, i shut it down. Feel free to try it out by cloning and following the "very helpful" README.
If you intend to put it up in production, do so at your own risk. But rememeber to move to a better backend. I used redis, cos thats another DB i am a fan of. I intended to use MongoDB initially but recently i have been trying to move away from Mongo but not decided on an alternative.
TL; DR; Overall Opinion
EcoSystem
Is it easy to get up and go?
Getting up and running with Deno is easy. But should you do it? If you are an early adopter, and intend to build a small application and do NOT have tight deadlines? Then you should only if your team is prepared to fend a little. Stack Overflow may not have enough developers to answer their questions, yet. It needs adoption, and that will take some time.
Is the toolset ready?
Toolsets such as IDEs are the same as existing, so no learning curve. Gulp, Grunt etc can be reused as before. Nodemon etc. and still not available. But can be overcome with minor modifications. I would rate toolsets availability as good.
Packages / Modules availability?
The compatibility and ability of using packages on npmjs adds a large advantage. And so i would dare to say that packages are available and are extensive. Finding a package is difficult. There is a need for a better search engine there. The current filter-as-you-type is not scalable.
Goals Met?
In terms of achieving the initially defined goals. I used Ryan Dahl's YouTube video (10 Things I Regret About Node.js - Ryan Dahl - JSConf EU - link) as a yard stick to look at whether it met the goals.
Usage of Promises
Promises are used extensively along with async await pattern. The usage is very similar to other platforms / runtimes. And it feels natural. Goal met.
Security 1
Deno needs you to explicitly "allow" the permissions to access network / other resources for the execution of the code. These need to be added as command line parameters. (Example- --allow-net for Network permissions). I did not like it. Why - In my experience, NodeJS primary use case has been to listen to requests via tcp protocol. Most other tasks are CPU intensive, so I do not use NodeJS. Listening on a port also needs the permission to be provided. So all my applications would need this flag. I feel the allow-net permission should not be needed for listening to ports, and should only be for external access.
Security 2
There is no defined way a package (3rd party or otherwise) can publish the permissions required for it to execute and there is no way our code can restrict the permissiosn provided to a 3rd party library / module. So there is no way to restrict a package from behaving in an "evil" manner. I had initially believed that this would be solved using a sandbox for third party modules. But maybe the overhead is too high. But that is something i wish existed.
Not using Gyp as a Build System
I believe this is a problem which NodeJS came up with because it always wanted to be backward compatible. Similar to how Python2 never went away because no end date was ever mentioned (until recently). Could it happen to Deno, maybe not Gyp, maybe a XYZ build system. Yes, it could. But thats not something which can be answered now. It will be answered based on how Deno matures.
package.json - NNN - No NPM Needed
Yes, no package manager is needed and none is installed. I liked it. Package management is decentralized. Excellent. But maybe work is needed to ensure that no MTM (Man In The Middle) attack compromises the integrity of the packages being used. There should be some mechanism of maybe hashing the file or similar, and recording the hash. But then that will make the application resistant to new minor versions / builds.
package.json - concept of module as a directory
I think this is good but will it tie packages to a domain name is something i need to test out. Example - if i create a package and host it at xyz.com/package1.ts. Within this if i refer to package2.ts in the local folder, should i require the whole path or only package2.ts? If the whole path is required it will be a challenge for moving across environments such as staging / qa etc.
node_modules
Yes this is not required, and it saves me from having to remember to add it to .gitignore every time.
require without extension and index.js
Met this goal. But the goal does not excite me much.
So overall, i believe Deno achieves the goals set initially. Some things i dont believe are good in terms of being able to scale the team size of developers involved. And other goals do not matter to me.
Would i use it for my next project? Doubtful. I do not see the benefit yet. I believe when developers in the current state will take time to get their tasks completed, and the gain we will get is not visible. Having TypeScript is something which I see as beneficial, but then NodeJS also supports TypeScript.
Lastly, I read many persons asking about whether to migrate all their code from NodeJS to Deno. To them - I dont understand why. NodeJS is gaining maturity every day. And contrary to the beliefs, Deno is not the "next" NodeJS. It solves different goals. The amount of work needed to move to TypeScript is huge (I dont think Deno supports JavaScript). yes, NodeJS has problems, so maybe if you are thinking of writing a new application, you need to consider.
So overall, should everybody jump the bandwagon and start using Deno for large scale production deployments.
- Short Answer: Not Yet.