DEV Community

Cover image for Nectarine Is Teaching KiwiEngine To Understand Applications
Drew Marshall
Drew Marshall

Posted on

Nectarine Is Teaching KiwiEngine To Understand Applications

So far, I've been looking at the individual pieces that are making KiwiEngine feel more like an actual engine.

Juice is becoming the design engine.

Sig is becoming the reactive UI engine.

Now I want to talk about Nectarine.

And Nectarine is interesting because its job is less visible.

You don't necessarily see it on the screen.

You don't click it.

It doesn't make something animate.

Instead, Nectarine is becoming part of the system that helps KiwiEngine understand what an application is.

That's a very different responsibility.

Configuration Can Be More Than Settings

When most developers hear "configuration," it's easy to think about a file full of settings.

Ports.

Environment variables.

Feature flags.

Database credentials.

Maybe some application metadata.

That's useful.

But that's not really where my interest in configuration ends.

I've been thinking about configuration as a way of describing a system.

Not just:

What value should this setting have?

But:

What does this application contain?

That's where Nectarine starts becoming much more important to KiwiEngine.

Describe More. Repeat Less.

Think about the amount of information that gets repeated throughout a typical application.

A model exists.

Then somewhere else, something needs to know its fields.

Something needs to understand validation.

Something needs to understand how it can be queried.

A route needs to expose it.

Documentation might need to describe it.

Another system may need metadata about it.

Pretty soon, the same concept exists in five different places.

And every one of those places can drift away from the others.

That's exactly the kind of repetition I want KiwiEngine to reduce.

If the engine already knows something about the application, I don't want to keep explaining the same thing to every subsystem individually.

I want to describe the intent once and allow the appropriate systems to understand it.

That's Where Nectarine Fits

Nectarine is becoming the configuration and schema layer that helps make that possible.

It gives KiwiEngine a structured way to understand things like application configuration, routes, models, and query metadata.

That means configuration stops being a passive file sitting somewhere in the project.

It becomes something the engine can actually reason about.

Not artificial intelligence.

Not magic.

Structure.

The application describes itself in a predictable way.

Nectarine parses that description.

Other systems can then use the resulting information.

That's a much more powerful relationship.

YAML Isn't The Interesting Part

Nectarine uses YAML heavily.

I like YAML for this kind of work because it can make structured configuration fairly easy to read.

But YAML isn't really the point.

I don't want Nectarine's identity to become:

The YAML library.

The important part is the contract.

The configuration has meaning.

The schema has meaning.

The engine understands what those structures represent.

YAML is simply one useful way of expressing them.

The value comes from what KiwiEngine can do once that information has been described.

This Is Another Form Of Intentional Programming

I've written before about something I've started calling Intentional Programming.

The idea is pretty simple.

Sometimes I don't want to describe every implementation step.

I want to describe what I'm trying to accomplish.

Juice does this visually.

When I say:

<div content adapt="grid" mobile="stack">
Enter fullscreen mode Exit fullscreen mode

I'm communicating design intent.

Nectarine applies a similar philosophy at a different layer.

Instead of manually wiring every piece of application metadata together, I can describe the structure the application needs.

Then the engine can handle more of the translation.

That's becoming one of the larger patterns across KiwiEngine.

Describe the intent clearly enough that the engine can handle more of the mechanics.

But Declarative Systems Can Go Too Far

There's a trap here too.

And it's the same kind of trap I've encountered with Juice.

Once configuration becomes powerful, there's a temptation to put everything into configuration.

Business logic.

Complex workflows.

Every possible behavior.

Before long, you've accidentally invented a programming language inside YAML.

I don't want that.

Configuration should describe the things that are naturally declarative.

Code should handle the things that are naturally procedural.

If a business rule is clearer in code, it should probably be code.

If something requires complicated branching behavior, forcing it into a configuration format doesn't automatically make the architecture better.

Nectarine shouldn't eliminate programming.

It should eliminate unnecessary repetition.

That's an important boundary.

The Schema Matters More Than The Syntax

This is another lesson I've learned while building these libraries.

A configuration system without a meaningful schema is basically structured guessing.

You can put values into a file.

But what do they mean?

What's required?

What's optional?

What's valid?

What does another system expect to receive?

That's where schemas become important.

They turn configuration into a contract.

Now the engine doesn't just receive arbitrary data.

It receives data with expected structure and meaning.

That makes validation possible.

It makes tooling possible.

It makes errors more useful.

And it makes composition between different systems considerably safer.

The Engine Can Start Connecting Dots

This is where Nectarine becomes especially interesting inside WebEngine.

Imagine the engine understands that a model exists.

It understands metadata associated with that model.

It understands routes defined by the application.

It understands configuration affecting those systems.

Now different parts of the engine can start working from the same source of truth.

That's a big difference from manually wiring everything together.

The application says what exists.

Nectarine helps interpret that description.

The appropriate engine systems figure out what to do with it.

That's starting to feel much closer to an engine.

I Don't Want To Write Infrastructure Logic Forever

This connects directly to why I'm building KiwiEngine in the first place.

I want to spend more of my time writing the logic that makes an application unique.

If I'm building WebStore, I want to think about commerce.

Products.

Orders.

Inventory.

Fulfillment.

Customers.

If I'm building something for Blackwater Sound, I want to think about artists, music, sessions, releases, lessons, and creative workflows.

I don't want every project to require another round of:

"How should I wire all of this basic application infrastructure together?"

Some of that information can simply be described.

And once it's described consistently, KiwiEngine can do more of the repetitive work.

This Doesn't Mean Zero Code

I think that's worth emphasizing.

I'm not chasing some fantasy where a sufficiently large configuration file replaces software development.

That would defeat the purpose.

The goal isn't:

No code.

The goal is:

Spend code where code matters.

Business logic matters.

Unique behavior matters.

Interesting algorithms matter.

Domain-specific workflows matter.

Those are places where I want the freedom and expressiveness of programming.

Boilerplate isn't where I want to spend most of my creativity.

If Nectarine can remove some of that repetition without hiding the architecture from me, then it's doing its job.

Nectarine Also Helps The Other Pieces Become More Powerful

This is where these library posts start connecting.

Juice can consume project configuration and generate styling behavior.

That's already an example of configuration becoming active infrastructure.

The project defines aspects of its design language.

Juice understands those decisions.

The appropriate CSS can be generated.

Now apply that idea beyond styling.

Configuration becomes one of the ways independent KiwiEngine systems can understand the application they're participating in.

That's important because I don't want those libraries tightly coupled to one another.

Juice shouldn't have to become Nectarine.

Sig shouldn't have to become Nectarine.

Other systems shouldn't each invent completely different ways of understanding project configuration.

A shared configuration architecture gives them a common language without making them the same system.

This Is How Composition Starts Becoming Practical

I've talked a lot about composition throughout this series.

It's easy to say:

Build small libraries and compose them.

Actually making that pleasant is harder.

The pieces need contracts.

They need conventions.

They need predictable inputs.

They need to understand enough about the environment they're operating in without becoming dependent on everything else.

Nectarine helps establish some of those contracts.

And that makes it more than a configuration utility.

It becomes connective tissue.

Not because every library needs to depend directly on Nectarine for everything.

But because KiwiEngine increasingly has a structured way to describe the application those libraries are helping build.

Another Piece Is Settling Into Place

This is why I'm spending time looking at these libraries individually.

KiwiEngine becoming an engine isn't one giant milestone.

It's happening piece by piece.

Juice is learning how to translate design intent into styling behavior.

Sig is learning how to make interfaces reactive.

Nectarine is helping the engine understand the structure and configuration of the application itself.

Each library answers a different question.

And the answers are becoming more stable.

That's what makes the larger architecture possible.

Because an engine isn't powerful simply because it contains a lot of features.

It's powerful because its systems understand their responsibilities and know how to work together.

Nectarine is helping KiwiEngine get there.

If Juice helps KiwiEngine understand how an application should look, and Sig helps it understand how an interface should react, Nectarine helps KiwiEngine understand what the application says it is.

And once the engine understands that, it can start doing a lot more of the boring work for me.

Top comments (0)