I am currently working on a silly little project that will post pet’s up for adoption every hour to mastodon. I am struggling with how I should structure the project.

Should I put every single step in it’s own typescript module, like the main file calls the petgrabber function in petgrabber.ts after 1hr, than petgrabber calls the mastodon function in the mastodon.ts file, or should I just do a single file, or is there a way I am not thinking of. My biggest thing is them being interdependent on each other feels like it defeats the purpose of having them in their own file.

  •  gender   ( @gender@beehaw.org ) 
    link
    fedilink
    English
    11 year ago

    In general there’s a balance to be struck between too few files and too many depending on the complexity of your code, but I can think of a few reasons you might want things to be split out for this project. One example would be to split initializing the mastodon client to its own file, then when you’re reading code that uses the client you don’t have to think about how the client was initialized.

    You’re right that it can be confusing when tightly coupled code is split between a bunch of files; to use your example it’d probably be cleaner to write petgrabber.ts as an independent function that returns a result, then have a ‘post to mastodon’ function that takes generic arguments, and call them both from the main file, taking the results from the petgrabber function, formatting them and passing them to your post to mastodon function.

  • Agreeing with WontonSoup here:

    Compartmentalize things so they all handle one thing individually and then you call those things from a main class is generally the way you’d do it.

    OP, one common approach here is that code for calling to an external dependency should be split out into its own module that’s called from some central place. That’s a fairly natural way to organize code that tends to provide a good separation of concerns – a lot of the times there’s some sort of messy logic about calling an api or pulling something from the database, and its nice to have all that set aside from the core logic of what your app is actually doing.

    As an app grows more complicated, you often end up wanting to add some additional layer. The result is a three-fold division at a high level: One “outer” layer dealing with the triggering context (e.g. an incoming http request), one core layer that handles any business/domain logic, and a third layer for handling all external dependencies. Then in each layer, you’d split things into specific files/modules based on grouped functionality.

    There are a lot of specific ways of implementing this arrangement (and a lot of ways it can break down!), but the main point is to prevent certain types of complexity from creeping into places its not necessary. You want a structure that’s easy to test, easy to reason about and navigate, and is easy to modify going forward.

    In your case it sounds like you could start pretty simply:

    1. An outer module/file for dealing with the triggering condition and its environment (which could be handling an http request, an executable invocation, a messaging bus signal, a scheduled job trigger, however you’ve set this up to run once/hour!)
    2. A core module that orchestrates the details of the process.
    3. One file/module each per type of external dependency.

    Likely #2 could be folded into #1 for a simple project like you have in mind. It is still a good idea to at least separate it into its own method. :) You’ll inevitably want to run it on demand (whether testing manually, or writing some sort of unit/integration test.)