Circular dependencies can be removed in almost every case by splitting out a large module into smaller ones and adding an interface or two.
In your bot example, you have a circular dependency where (for example) the bot needs to read messages, then run a command from a module, which then needs to send messages back.
v-----------\
bot command_foo
\-----------^
This can be solved by making a command conform to an interface, and shifting the responsibility of registering commands to the code that creates the bot instance.
main <---
^ \
| \
bot ---> command_foo
The bot
module would expose the Bot
class and a Command
instance. The command_foo
module would import Bot
and export a class implementing Command
.
The main
function would import Bot
and CommandFoo
, and create an instance of the bot with CommandFoo
registered:
// bot module
export interface Command {
onRegister(bot: Bot, command: string);
onCommand(user: User, message: string);
}
// command_foo module
import {Bot, Command} from "bot";
export class CommandFoo implements Command {
private bot: Bot;
onRegister(bot: Bot, command: string) {
this.bot = bot;
}
onCommand(user: User, message: string) {
this.bot.replyTo(user, "Bar.");
}
}
// main
import {Bot} from "bot";
import {CommandFoo} from "command_foo";
let bot = new Bot();
bot.registerCommand("/foo", new CommandFoo());
bot.start();
It's a few more lines of code, but it has no circular dependencies, reduced coupling, and more flexibility. It's easier to write unit tests for, and users are free to extend it with whatever commands they want, without needing to modify the bot
module to add them.
I suspect to get downvotes into oblivion for this, but there's nothing wrong with the concept of C2PA.
It's basically just Git commit signing, but for images. An organization (user) signs image data (a commit) with their public key, and other users can check that the image provenance (chain of signed commits) exists and the signing key is known to be owned by the organization (the signer's public key is trusted). It does signing of images created using multiple assets (merge commits), too.
All of this is opt-in, and you need a private key. No private key, no signing. You can also strip the provenance by just copying the raw pixels and saving it as a new image (copying the worktree and deleting .git).
A scummy manufacturer could automatically generate keys on a per-user basis and sign the images to "track" the creator, but C2PA doesn't make it any easier than just throwing a field in the EXIF or automatically uploading photos to some government-owned server.