PretendoNetwork / nex-protocols-common-go

Reusable implementations of NEX methods found in many servers
GNU Affero General Public License v3.0
19 stars 8 forks source link

[Enhancement]: Become opinionated #37

Open jonbarrow opened 4 months ago

jonbarrow commented 4 months ago

Checked Existing

What enhancement would you like to see?

Become a bit more opinionated with our implementations. Right now we try to be as unopinionated as possible, in order to give 3rd party developers more freedom for implementations. For instance with DataStore, we opt to do NO database handling, so that if someone else wanted to use our libraries and use a different database then they could

I 100% still feel like we should give this level of customization. However this DOES result in quite a bit of duplicate code between our servers, which is also not great. @ashquarky has proposed adding a 4th library to our stack as a middleware, but I think we can do better

Now that @DaniElectra is using Postgres in #35, this gives us a bit of wiggle room to be more opinionated here. Rather than exposing a ton of helper functions in protocols like DataStore, and forcing the developer to define them all with their preferred database, we can instead make a default implementation here and then export the relevant functions as struct fields rather than exporting them as methods. Having them as fields lets them be overwritten, whereas methods cannot

As an example:

package main

import "fmt"

type DataStoreCommonProtocol struct {
    GetObjectFromDatabase func()
}

func (d *DataStoreCommonProtocol) getObjectFromDatabase() {
    fmt.Println("Built in")
}

func customGetObjectFromDatabase() {
    fmt.Println("Custom")
}

func NewDataStoreCommonProtocol() *DataStoreCommonProtocol {
    d := &DataStoreCommonProtocol{}
    d.GetObjectFromDatabase = d.getObjectFromDatabase // Assign our default implementation handlers

    return d
}

func main() {
    d := NewDataStoreCommonProtocol()

    d.GetObjectFromDatabase() // "Built in"

    d.GetObjectFromDatabase = customGetObjectFromDatabase

    d.GetObjectFromDatabase() // "Custom"
}

This example shows how we can have our own implementations, which we would then use internally, but still allows them to be overwritten by the developer if they want to use their own database

The only thing this lacks is the ability to reference unexported fields in a custom implementation, but that would be the case either way so it's not a huge issue in my opinion?

A downside to this would mean that if we discover something new in one of these protocols, we have to wait for common to update. And we lose a bit of control over things like schema structures and the like. I'm not sure how much we care about that though

Any other details to share? (OPTIONAL)

No response