This weekend, I started my first project in and wanted to share my experience with the community. This includes those who are curious about Nim but are yet to try it and the more involved alike. So, let’s start with the story behind! Nim Background I’m a Computer Science BSc. student in Hungary, Debrecen, mostly experienced with Java and JavaScript and with some background in functional (F# to be precise). programming These can be seen as mainstream languages with excellent tooling and a vast number of third-party libraries. Basically there’s a lib for every task one can come up with. And in most cases, not just one lib, but at least a handful of them. Apart from the actual language features, the available libs and tools play a crucial role when comparing languages. I’ll talk about this later, but wanted to start with it. What’s Nim? Nim is a general-purpose statically typed and compiled programming language with a strong metaprogramming support. It’s super-fast (both the compilation and the execution) and has a nice, clean syntax. The language goes to great lengths to support interoperability with other languages (for example C or C++) through the Foreign Function Interface. That way, although Nim has its own package manager, one can easily utilize libs written in other languages. This is just a short introduction, and I could write a lot more about Nim but it’s better if you check out the official site: _The Nim programming language is a concise, fast programming language that compiles to C, C++ and JavaScript._nim-lang.org Nim programming language | Nim RealWorld RealWorld is a fairly new initiative by Thinkster. It’s intended to show you how to write the exact same app (a Medium clone actually) using different frontends and backends. These all adhere to the same API specification therefore can be mixed and matched freely. More information at here: _🏅 Exemplary fullstack blog apps powered by React, Angular, Node, Django, and many more — it’s like TodoMVC, but for…_medium.com Introducing RealWorld 🙌 This offers a great way to compare a wide spectrum of platforms and learn the best practices of the tech of your choice. Anyone can contribute but only seasoned developers are advised to do so. RealWorld puts a strong emphasis on readability and the use of well-established best practices. Inexperienced devs might not be able to produce implementations that follow these principles. Weekend Hackathon Motivation Approaching the end of my university studies I’m a bit overwhelmed by more important stuff to do, yet I wanted to take this as a weekend hackathon challenge. As I’ve written before, I haven’t really worked with a native language since ages (apart from being a computer graphics TA and using C). The features of Nim have really appealed to me, and I wanted to give it a shot. Of course, I’ve written the mandatory programs, but that’s not a serious test drive. However coming up with small scale projects is not easy for me, that’s why I was immediately attracted by the idea of RealWorld. Hello Word & co Still, I shouldn’t have started an official Nim implementation just for this reason. “ ?” I asked myself. The answer to this question was the real fuel to my project: “ ”. As a consequence, I’ve relied on my intuition and Java/JavaScript experience. How am I going to use the best practices with my lack of experience There are no best practices — yet. The implementation is on GitHub at: _nim-realworld-example-app - Nim implementation of the RealWorld example app_github.com battila7/nim-realworld-example-app Environment I downloaded the latest published version of Nim directly from the official site. The compiler is nim 0.16.0 and the package manager is nimble 0.8.2. The dev machine ran a 64 bit Ubuntu 15.10. Choosing the framework One can work directly with Servlets in Java or write vanilla http code in node. But that’s rather the case, in most situations we choose a framework that’s going to do the heavy-lifting for us. In Java I’ve been using Spring/Spark and hapi/express in node respectively. Of course there is a tremendous amount of frameworks but in my opinion these are some popular ones. Nim offers the same: We can roll vanilla (asynchttpserver) or choose the right tool. Nevertheless we can only find two web frameworks, and . Jester Rosencrantz Jester is the more popular option and is developed actively by a core Nim contributor, Dominik Picheta (who wrote the excellent book). Seems like a sensible choice, yet I settled with Rosencrantz. As far as I know, Jester won’t let me split my route definitions, they must sit in the same file (see ). This can be seen as an advantage, but when developing a larger or even medium scale application this is clearly not beneficial. The combinator approach of Rosencrantz and its wider range of features out-of-the-box also helped my decision. Nim in Action this issue Best Practices The essence of this article is to start a community process which can result in an agreed-upon set of best practices about Rosencrantz and in general Nim code and can make its way to the — currently short-spoken — . Nim Style Guide import judiciously The way we import other modules is crucial to make our code readable. I came up with the following: Use at first place. That way it’s always clear where different procs and types comes from. For self-written code, this rule should almost always apply. from module import x, y, z When importing the standard library, or importing a large number of items from the framework, use naked for conciseness. same import Use in favour of the module you’re actually using, ie. exclude from the standard library. except When you find yourself excepting a lot, or using qualified names, use the statement and force qualifying everywhere. from module import nil Alias imports only with the previous syntax: . from module as m import nil import order import modules in the following order so it’s always clear, where the modules come from: Standard library Third-party packages Self-written code import vertical spacing Put an empty line between the aforementioned sections and leave two empty lines after the last section. Emphasize the public interface Sometimes the documentation of a module is not enough to understand the way it works or the way it should be utilized. Consumers of the module can only access its public interface. These are the declarations marked with the export symbol. When placing stuff around in a module, always put an emphasis on exported declarations. For example, forward declarations of the exported should come before module-private . Again, exported types should precede private types, furthermore they should be declared in different sections. procs procs type Write your templates/macros Instead of boilerplate code, don’t fear to write a template or a macro. Although this puts an additional layer of indirection on top of your code, it saves you time and if written correctly, increases code readability. Since metaprogramming in Nim is quite easy, anyone can come up with clean solutions to ugly problems. However writing useful and readable templates/macros takes practice. Use these constructs to solve problems, don’t bend the problem to them. Make them look like an intuitive clean syntax, and not like some black magic you can satisfy your inner computer science pervert with. Result first The implicit variable is a quite handy feature. Most of the times, it can be used as a fallback return value in conjunction with naked s. In that case, setting the value of should be the first statement of the procedure body. result return result Return Option[T] Use exceptions for exceptional cases. Sometimes not being able to produce a result is perfectly acceptable. In situations like that, use the type which can indicate whether a result was produced or not. This approach is superior to returning a tuple of type or throwing unnecessary exceptions. Option[T] (bool, T) Fail them Futures Async code can fail too. One might be tempted to use but I consider that a bad practice because Future can itself express failure. However in order to fail a Future, an exception of some type must be passed to it. My advice is to either use descriptive exceptions if the failure deserves that or use some general when you’re not interested in the reason behind the failure, just the failure itself. Future[Option[T]] NoResultAvailableError let where you can, var where you must The title speaks for itself. Using one-time assignable variables makes the code easier to reason about and can some hard to get all-nighter bugs. Ideally, you should find yourself using var rarely. Const is even better, but it has different use cases. do the do notation Passing anonymous procs to other constructs should always be done (when possible) using the notation. It eliminates unnecessary syntactic noise (proc and parentheses) which results in pleasant reading and writing experience. do Best Rosencrantz Practices Compose with -> instead of [ ] Rosencrantz provides to operators to compose handlers: and . The documentation states that the syntax is nicer when composing a large number of handlers. I think the opposite. -> [] [] expresses composition better because it looks like what its effect is: composing handlers after one each other. It doesn’t have a closing pair as does therefore won’t produce as much noise, seems like more idiomatic Nim code. -> [ Split routes: never use -> and ~ together Rosencrantz offers another operator which can be used to create alternative paths. Using and together is great, but results in a hard to read and even harder to maintain code. We all know, that typing a bit more now will save us from bigger problems in the long run. With that in mind I advise the following. ~ -> ~ Create (with all verbosity) all handlers in a let statement (using only operators) and then combine them with the operator. Somehow like this: -> ~ letgetSingleUser =get ->pathChunk("/api/users") ->segment do (username: string) -> auto:ok(username) getUsers =get ->path("/api/users") ->ok("Users") let handler =getSingleUser ~getUsers All routes stand on their own and can be freely modified. Also, because they are assigned to individual variables, the name of these variables can act as a small piece of documentation. This style might be verbose, but it will definitely pay off. Create your own handlers Rosencrantz can definitely do some cool stuff, but most of the exercise is left to the developer. When creating a web API, the topmost layer should be responsible for input validation, authentication and authorization, input parsing and the correct representation of the output. These tasks should be done in all of the application’s routes and rewriting over and over is cumbersome and error-prone. Fortunately, Rosencrantz is easy to extend with custom handlers. Use this feature to extract the aforementioned tasks into custom handlers. That way routes will only include the necessary and specific logic. Bad Parts I’d also like to point out some of the currently bad or missing parts that should be enhanced in order to provide a more streamlined developer experience. This is just a quick and dirty list, and most of the things might be already fixed on the bleeding edge branch. Unique module names You cannot create two modules with the same name. So using and is prohibited because is not unique. This restriction should be removed. model/user service/user user import failure When importing a module that contains a declaration that has the same name as the module, the compilation fails. Importing from crashes the compiler. handler article/handler Cryptic template/macro error messages Not as bad as the C++ counterpart but the error messages produced by erroneous template instantiation or macro execution should be more friendly. Third-party packages This is not a problem with the compiler or the tooling, but an overall problem with the Nim ecosystem. For a specific task, only one or two solutions exist or no third-party package exists at all! Even though C libs can be used, that does not compensate the lack of pure Nim or even wrapped C libraries. Conclusion Nim has a huge potential because it’s fast, clean and easy to use. However the compiler and the tooling is still not stable and the number of third-party packages is quite small, and most of them is not even maintained any longer. It also misses well-established best practices and agreed-upon methods. These are the biggest obstacles preventing Nim from getting more popular. And now about RealWorld… The weekend is over, and so is my hackathon. I’ve set up the environment (frameworks, DB) and developed a stable foundation which I’ve also implemented the routes upon. The profiles and articles routes are still to be done, but unfortunately I won’t have too much time for them. For that reason contributors are warmly welcomed :) /api/users Taking everything into account, I had a great time working on this project. Nim feels like a breath of fresh air after all those VM/managed/interpreted languages. Sometimes it requires a bit of plumbing, but overall provides a pleasant development experience. Highly recommended! is how hackers start their afternoons. We’re a part of the family. We are now and happy to opportunities. Hacker Noon @AMI accepting submissions discuss advertising & sponsorship To learn more, , , or simply, read our about page like/message us on Facebook tweet/DM @HackerNoon. If you enjoyed this story, we recommend reading our and . Until next time, don’t take the realities of the world for granted! latest tech stories trending tech stories
Share Your Thoughts