// Validate .env file
const { validate } = EnvValidator
const validationResult = validate()
// This comes from neverthrow
if (validationResult.isErr()) {
logger.trace('Wrong .env file config:', validationResult.error)
} else {
// Mount app
const app = createApp(App)
// Provide logger to Vue IoC
app.provide(IocEnum.LOGGER, logger)
}
#How Can I Reduce The Nesting?
72 messages · Page 1 of 1 (latest)
i assume your program just terminates in the error case? this might seem bad since you're using neverthrow, but IMO throwing is perfectly legitimate for fatal problems like "i can't read the config":
// Validate .env file
const { validate } = EnvValidator
const validationResult = validate()
// This comes from neverthrow
if (validationResult.isErr()) {
logger.trace('Wrong .env file config:', validationResult.error)
throw new Error('Cannot start app')
}
// Mount app
const app = createApp(App)
// Provide logger to Vue IoC
app.provide(IocEnum.LOGGER, logger)
all else being equal, i think that's actually better behavior as it'll make your program terminate with a nonzero exit code in the error case
I like this more
I don't need an error for expected stuff
That's my philosophy
I just don't know how to exit without an error.
I don't know if I can use process.exit() like in node here, but I guess not.
what's wrong with throwing like i showed above?
how to exit without an error
do you mean that you don't consider this to be an error?
yes
its an error but an expected error
and that is not really an error for me
ok it is a warning for me
it's expected for users to have invalid .env files?
maybe this is just a semantic thing, but that sounds super weird to me. by your definition should ls --someOptionThatDoesNotExist exit with 0?
I don't know if you can compare it with a cli tool
it's not like i would check the return code anywhere
i use exit codes all the time, even for servers. in fact i have my PROMPT set up to indicate the success/failure of the last-run command, and do stuff like some-program || do-something-else fairly often
i too am a fan of result/either/monads, but when it comes to fatal problems i want to fail loud and fast. and i most definitely want to make sure users are aware of them
but anyway, you also said:
I don't know if I can use process.exit() like in node here
what's your runtime?
but not on exit code level
what would be an "exit code level" error in your mind?
when the sqlite package can't be installed due to some environmental constraints
what if it can't be installed because of invalid configuration somewhere? is that no longer an error?
when i see a mysql error this is a red flag
"your config file is wrong" is about as fatal as i can imagine. maybe like "my program doesn't even support your architecture" is worse
anyway i can move past this if you're set on it
yeah okay that's a good argument
if you can reply to this i can probably give advice
Yeah sure, I am really open here, although it doesn't seem like it.
Because you already said you like monads and I don't hear that a lot.
FWIW i feel that process.exit(0) is even more anti-FP than throwing. at least with throwing there's the possibility of recovery or doing cleanup or whatever, whereas process.exit feels even more non-local
the FP way would probably be piping or otherwise composing your startup sequence into one big result/either, then having a single block at the end handling the error case
I think I will change my opinion to fail fast on critical stuff
And loud
with an error
I still can use my no-throw philosophy for smaller errors
But I can't imagine some examples
Maybe the status endpoint of xyz is down but the service is alive
Nah thats too big
maybe i have 5 sources for the same thing and 1 source goes down
that's an error but not a critical one
or validation errors but not for .env
think within your program: like getUser(idWhichDoesNotExit), or sendEmail(invalidEmailAddress) or whatever
yeah
have you heard the philosophy "push side effects to the edges"?
your program is going to have side effects if it does anything useful, but the FP way is to have those entirely contained at the "top" of your program (like in this case the example you showed is probably the equivalent to main(), right?)
yes it is in my main.ts
i know philosophy about writing uncoupled code to keep side effects minimal
like composition over inheritance
but your exact phrase i can't remember from somewhere
i typically will have zero side effects anywhere except within stuff done during my app startup sequence. if i need to access a database or whatever i'll create the database connection once at the top and pass it down, so deeper code doesn't directly do any side effects, just calls methods on a dependency
i usually like to build dependency containers
yeah, same idea i think
and export it as singleton on es module import export level
its just i throw all instances in one or more grouped containers, export it and ez
the container is just an object
and then i can pass the container
and get my access everywhere
without threatening the di principle
i even did one time an injection/an addition of a property into the discord bot js library xD
because i imported the lib everywhere i could use the attached item everywhere
that was the og hack xD
but i think this wouldn't work on strict ts. there, i used js,