this post was submitted on 20 Aug 2023
4 points (100.0% liked)

Transprogrammer

818 readers
1 users here now

A space for trans people who code

Matrix Space:

Rules:

founded 1 year ago
MODERATORS
 

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.

top 3 comments
sorted by: hot top controversial new old
[–] WontonSoup@lemmy.world 3 points 1 year ago

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.

Splitting things up will make your classes specific to a certain functionality and allow you to keep track of everything without individual files being thousands of lines, though sometimes they will end up that way anyway to achieve a single piece of functionality.

So for example you might have a service to call the api to get data, a service that exclusively posts to mastodon, etc.

You can write 500 lines of code to do something in your service and hide it away but then just call it like petInfoService.getPetInfo() from your main class and when you look at the flow it’ll make a lot more sense.

Any reason you chose typescript out of curiosity? Nothing wrong with it, just curious.

Feel free to post code if you need help. Just make sure whatever you’re posting or uploading to git doesn’t include any API keys.

[–] gender@beehaw.org 1 points 1 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.

[–] amethyst@lemmy.blahaj.zone 1 points 1 year ago* (last edited 1 year ago)

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.)