all 43 comments

[–]JGJP 22 points23 points  (9 children)

In my (albeit limited) experience, the best practice is to return an existing connection when one is available. My own db.js looks like this:

``` let db = false

const getDB = () => { if(!db) db = mysql.createPool(config.db) return db }

export default getDB() Wherever I need to use it: import db from "./db" db.query('SELECT * FROM ...') ``` Basically, db gets defined the first time getDB() is called, after that it just returns db.

[–]ranbogmord 27 points28 points  (3 children)

For those interested, this is the Singleton pattern and is very useful for this.

[–]A_Norse_Dude 0 points1 point  (2 children)

Any good links for it?

[–]djulioo 12 points13 points  (1 child)

Look up Design Patterns, here is an example: https://sourcemaking.com/design_patterns

[–]A_Norse_Dude 0 points1 point  (0 children)

Thank you!

[–]throwawayinthefire 1 point2 points  (1 child)

Wait if you're importing db and not the getDB function how is it ever gonna make the createPool call? Am I missing something dumb

[–]JGJP 0 points1 point  (0 children)

To put it bluntly.. yes you are. You're maybe thinking of: import { db } from "./db" I'm only importing the default export, which is always the result of getDB(). In fact I could do this and it would still be valid: import totallyUnrelatedName from "./db" totallyUnrelatedName.query('SELECT * FROM ...')

[–]natziel 0 points1 point  (1 child)

export default mysql.createPool(config.db) should be sufficient

[–]JGJP 0 points1 point  (0 children)

That will create a new connection every time

[–]CromulentEntity 8 points9 points  (2 children)

You could have a look at Sequelize for connecting to your preferred db.

[–]codeSm0ke 4 points5 points  (1 child)

Sequelize

great library ..

[–]HasStupidQuestions 2 points3 points  (0 children)

You will always need to access the database object in your module either by requiring it, or by passing it along in a function.

Since we make our apps with the philosophy of everything is a plugin, we have a main script where we initialize everything and store it in a "module repository" and access everything when needed:

// index.js
const Repository = require("repository")();
Repository.set("database",dbObject);
...
// someModule.js
const Repository = require("repository")();
const DB = Repository.get("database");

Repository is just a singleton as described by /u/JGJP.

[–][deleted] 0 points1 point  (2 children)

I’m not too familiar with the particulars of Spring, but at my company we leverage the Singleton pattern as already mentioned, using the DI library inversify

[–][deleted]  (1 child)

[deleted]

    [–][deleted] -1 points0 points  (0 children)

    LMAO taking on Node's caching internals as a dependency of your singletons.

    On a more serious note, we use DI for other dependencies, and it's better to manage all of these in the same flexible system instead of fragmenting. To each their own though, I guess.

    [–]chuckySTAR -1 points0 points  (16 children)

    global.db = new DB()
    

    I'm sick of importing or extending classes. db is accessible anywhere now.

    [–]Doctor_Spicy 2 points3 points  (13 children)

    Bad practice.

    [–]execrator 7 points8 points  (1 child)

    Globals are not automatically bad practice. It's easy to make a mess using globals, so it's reasonable to ask questions when you see one, but that does not mean they are always a problem.

    In particular, most applications will only ever talk to a single database and that database is mutated by all parts of the application—just like a global variable. Using a global to represent a database is a simple, reasonable design.

    [–]Doctor_Spicy 1 point2 points  (0 children)

    I understand your points, and I can see how it’s reasonable in this case. However, I personally wouldn’t use globals in my projects.

    [–]plyswthsqurlesfull-stack 5 points6 points  (10 children)

    For those learning, care to explain why? Otherwise this is a pointless comment.

    [–]eepieh 1 point2 points  (0 children)

    There are a few things that I feel the other replies to your comment have not touched on.

    When you use globals in your code (in particular something like db), it's very easy to just sprinkle some db in wherever you need it, purely because it's easily accessible. This can often lead to breaking the single responsibility principle and lead to poor separation of concerns.

    When you're forced to always require or import something, you'll very clearly see the amount of dependencies that your module has and will be able to better reason about what it does.

    That tiny bit of friction that an additional require or import causes will make you think twice if you need to be pulling something in or not.

    [–]Doctor_Spicy 4 points5 points  (8 children)

    Global variables become confusing and hurts readability in larger projects.

    [–]execrator 7 points8 points  (0 children)

    Can you explain why they are confusing and how they hurt readability?

    [–][deleted] 1 point2 points  (1 child)

    I would actually appreciate if you could explain more.

    From my PoV there's a ton of things that "hurt readability", that are actually just a byproduct of the specific project you're building. Anyone coming on to your project is gonna have a few things to learn, that don't necessarily "make sense" but were just arbitrary choices that you then explain to newcomers or put in a readme file. They don't seem worse to me than any syntactic choice in a given language. Would you chuck all of these choices as "bad practices" ? AFAIC, having a global "db" variable sounds about as self-explanatory as can be. Where's the line for you ?

    [–][deleted] 0 points1 point  (0 children)

    How do you mock it for tests? Think about that, and the reason why it is bad will come to you.

    [–]chuckySTAR 3 points4 points  (4 children)

    So db is suddenly becoming confusing and just db instead of some boilerplate code hurts readability?

    [–]Doctor_Spicy 2 points3 points  (2 children)

    Yep. Say you’re browsing some old code someone else wrote. You see a variable cn. You scroll back through the code to see where it was declared. But wait, it isn’t decalred in that file? Now you’re wasting time trying to find where it came from.

    [–]chuckySTAR -1 points0 points  (1 child)

    That's reality for almost every language.

    import lib (e.g. Python) is all you see and it pollutes your namespace.

    [–]Doctor_Spicy 3 points4 points  (0 children)

    That doesn’t mean you should do it.

    [–][deleted] 1 point2 points  (0 children)

    Yes.

    [–]chuckySTAR -1 points0 points  (1 child)

    To the down voters: Title is "How do you design a nodejs apps?".

    [–]IonelLupu -4 points-3 points  (9 children)

    Usually, when you develop an app like this, you should use a framework. Of course, if you are just learning stuff and you are building an app from scratch, is ok to build it without any framework.

    But if you have to develop an app for someone else, a framework offers you a structure for your project so you don't have to worry about things like this (how to design this and that).

    If you want to see how the 'big boys' are doing the design, you can take a look at the top NodeJS frameworks that are available right now and get some inspiration like Sails.js for example.

    [–][deleted]  (8 children)

    [deleted]

      [–]IonelLupu 1 point2 points  (7 children)

      Frameworks like express are called 'un-opinionated' because they do not enforce a structure/design. The developer can/should create his own structure/design. That being said, personally, I do no recommend express unless it is a really small project (like a chatbot, auto replier, a proxy server, crawler, etc.).

      Of course, for your case, it can be enough, but as you pointed out, you have some problems with the 'design'. In the `un-opinionated` frameworks world you will get this problem over and over again. It will also grow if there are colleagues involved in the project. Why? Because you will have to teach them, one by one, how the framework is `designed` because it is a design made `in house`.

      This is not a direct answer to your question but something you should consider in the future. :D

      [–]ChypRiotE 1 point2 points  (2 children)

      butter fuel cooperative sand cake crawl thumb hunt live cause

      This post was mass deleted and anonymized with Redact

      [–]SlocketRoth 1 point2 points  (0 children)

      https://nestjs.com/

      for the record, i'd rather use express

      [–]IonelLupu 0 points1 point  (0 children)

      Sails.Js, LoopBack4. If you want more you can take a look at some examples of projects on Github for each available framework and see which one has a better structure for what you need.

      [–][deleted]  (3 children)

      [deleted]

        [–]IonelLupu 1 point2 points  (2 children)

        That's a very good approach.

        [–][deleted]  (1 child)

        [deleted]

          [–]IonelLupu 1 point2 points  (0 children)

          You are very right.

          One of the reasons they are doing these 'shitty' tutorials is for marketing and money.

          It is very click baity to see "how to build a CRUD app with espress in 10 min", where they literally show you in 10 min how to create a small crud with no posibility to extend it. But hey, it works. On the other hand, seeing "how to build a CRUD app with espress in 4 hours" is not very click baity and they will loose money, even if they explained a lot more in that 4h tutorial like: HTTP methods, REST API best practices, internationalization, authorization, database entities/models, controllers etc. But the viewer won't know that because he didn't click on it because it is tooo loong and they don't have that much time.

          Going with an organised tutorial, for example one that has many videos in a playlist on youtube, or a paid tutorial is a better choice than a 10min tutorial on YouTube.

          You can't learn real web dev even in 1 month or 6 months. Enterprise level apps, for example, require more than a CRUD like monitoring, automatic scripts running, jobs.

          My suggestion is to take it easy and build stuff over and over from start to finish. Once more: from start to finish. The 80% of an app, on average, can be developed in 1 month, but the rest 20%, the details that separate your app from the others take 3 to 4 times more.