-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Smoother API Surfaces #47
Comments
Looking into restructuring the layout of the public API, both in how you import from it, and how the exported functionalities are named. When I check out how people are using the library, it seems like they don't read the documentation too closely (understandable), so they use extra API calls that don't have to be there. It seems like people want to use `NBT.parse()` more than `NBT.read()`, while one is for binary files, and one is for SNBT files. I can see how they might think `read()` is for reading from the file system, and maybe instead they think `parse()` is to just read arbitrary data. NBTify is meant to be used specifically outside of the file system though, so neither API feature would worry about that. Not all libraries are like that though, so I can see why people think that. #47 This is a demo I made the other day of how it might make sense to see the public API look. This commit experiments with that as a demo in mind. ```js // @ts-check import { Buffer } from "node:buffer"; import * as NBT from "nbtify"; const buffer = Buffer.alloc(25); const data = await NBT.readBinary(buffer); NBT.writeBinary; NBT.readString; NBT.writeString; ```
Another part of the confusion might be my current documentation around the module exports too. Originally, I liked the concept of modeling NBTify's module usage to be similar to that of the built-in // Namespace take
import * as NBT from "nbtify";
declare const buffer: Uint8Array;
const data: NBT.NBTData = await NBT.read(buffer);
const recompile: Uint8Array = await NBT.write(data);
const stringed: string = NBT.stringify(data);
// This would be `NBT.NBTData` as well, except that SNBT doesn't have any
// binary format options, so it wouldn't make sense to return those I think.
const destringed: NBT.RootTag = NBT.parse(stringed); // Named import take
import { read, write, parse, stringify, type NBTData, type RootTag } from "nbtify";
declare const buffer: Uint8Array;
const data: NBTData = await read(buffer);
const recompile: Uint8Array = await write(data);
const stringed: string = stringify(data);
const destringed: RootTag = parse(stringed); So the first initial step would be to look into renaming these exports, and making the namespace import just a choice, rather than a recommendation. The names should stand out enough on their own to make sense as a named import alone, without needing context of the namespace. // Updated named imports
import { readBinary, writeBinary, readString, writeString, type NBTData, type RootTag } from "nbtify";
declare const buffer: Uint8Array;
const data: NBTData = await readBinary(buffer);
const recompile: Uint8Array = await writeBinary(data);
const stringed: string = writeString(data);
const destringed: RootTag = readString(stringed); I think this can help distinguish which parts of the API are meant for NBT, and which are for SNBT. I thought this would be more apparent, but I think I was using it more as a gimmick or something. |
The other parts around things like In other libraries, some seem to return a tuple with the data object, and the other with the format options object. I do like this approach, but it means you have to destructure a specific part of the result in order to access the value, and passing it back and forth between I guess |
Another example demo I started conceptualizing with, this is the kind of thing I intend and personally use NBTify like. import { readFile } from "node:fs/promises";
import { readBinary, readString } from "nbtify";
const buffer = await readFile("./hello_world.nbt");
const nbt = await readBinary(buffer);
const string = await readFile("./bigtest.snbt", "utf-8");
const snbt = await readString(string); |
What makes for a nice API to use? I want NBTify to be usable in a plain ESM context (accessible by CDN from the browser), so import specifiers can't be too complex, things like that.
My main concern is that it seems like when I find people using NBTify in the wild, they mix up how features are meant to be used, and I think it's because the names I chose for the APIs aren't as explanatory as they could be. I am looking into how this could be improved, and how to make it more obvious as to how NBTify accomplishes it's design goals, without having to explain it outright to new users; it should just click!
The text was updated successfully, but these errors were encountered: