Human beings approach every new experience with a set of expectations, a mental model of what that experience will be about, and the more experienced we are, the more concrete that mental model is going to be. Going to a superhero movie, we expect lots of brawling, and when test driving a new car we expect the steering wheel to be in the same place.

Fiction writers call this mental model the premise, and fiction readers come to every book with a premise in mind. You violate the reader's expectations at your peril: the reader came expecting one thing and if you don't deliver, you'd better have a damn good hook that gives them a reason to read on, finish the book, and recommend it to friends.

The same thing is true of open-source software. Both the user's experience and the code layout should map to something the user is already familiar with. Too much similarity, with just a few "minor" changes, can be frustrating: the Rust versions of the veritable Unix 'find' command are brilliant, but they're just close enough to the original in functionality that it's hard to justify keeping both sets of command line rules in your head-- and everyone who uses 'find' is someone who does this for a living, has to work with many different machines, and knows 'find' will be the only choice on most of them. They don't want to learn a different model. They just want better tools.

I've recently had this experience with Django. I used to be a Django expert, a hired gun who customized Django administration engines and crafted high-performance query systems. I haven't worked much with Django 2.0, and now that I have I feel completely lost at sea. Despite my love of the declarative power of Haskell, I have not yet found a mental model for how Django, Django/Rest, and Django/Serializer interact. Part of the problem may be that the project I'm addressing was written by junior engineers who may have simply pasted what they found from Stack Overflow and messed with it until it worked. But my mental models of how Django works do not map well to this project.

So here's my recommendation: If you're re-implementing something "in Rust" because "Rust is better than C" (and it is, and I won't argue people who want to claim otherwise), support the existing functionality 100%. Support everything; if you find a bug, report it to the original maintainers. Add functionality only after you've achieved parity. Users often don't want something different; they want a better version of the same.

(That said, there is a time and a place for doing something different. Nobody knew we wanted the automobile, we just knew we wanted horses that didn't poop all over the city streets. On the other and, I question the eternal impulse for bigger, faster database engines when most people barely need MySQL circa 2007.)

More importantly, when you're laying out the project, lay it out in a way that's familiar to other users. Use a similar layout and even possibly a similar naming scheme for the basic components. Rust does some of this, with it's '' and '/bin' conventions, but to really meet other people where they live, you have to go further. Anticipate and meet their mental models somewhere in the middle, and you'll have them hooked into downloading, understanding, and maybe even participating in your project's vision.

And when you can't, when what you're doing is so new that few popular models exist, it's incumbent upon you to document both the why and the win of your method. It's not enough to say why you're doing something, you have to explain the win of doing it your way so clearly that people are willing to struggle with the code to understand the new thing that you're doing and wrap their heads around your new ideas.

Like any story, your code base has a premise, both a reason for existing and a plot by which you brought it into the world. Make those premises explicit and familiar, and your project will have an easier time finding users and contributors.