045: Gomponent with Markus Wustenberg

Dominic:

Hello there, I'm Dominic Sampiare and you're listening to Go Bugast. Today I'm joined by Markus Vistenberg and we talk about component. Hey, just before we start, I'd like to let you know that I just created a Go podcast channel on the Gopher's Slack community. So, if you are on there, I would appreciate if you, if you want to join. So, it's Go Podcast in one word.

Dominic:

And on that, I leave you with my interview with Marcus. Hello, gophers. I'm joined by Marcus today. He is the author of Components. So thank you very much, Marcus, for joining me today.

Markus:

Yeah. Hi, Dominique. How's it going?

Dominic:

Very good. Very good. So I usually start by asking guests to introduce themselves. You know, you can talk a little bit about where you're coming from, what you are doing at the moment, and where you are going. Not really, you know, specifically about Gamppon, and we will we will dive deep into that subject, but, you know, just just so we have a a small background on yourself.

Markus:

Right. So I'm Markus. I live in Denmark in a, well, comparatively small city called Oost together with my girlfriend and 2 kids. I'm an independent software developer, so I do consulting as well as building small products on the side, doing open source work and, yeah, that kind of stuff. So it's just me in my little company, and I'm very much enjoying myself.

Dominic:

That sounds great. When you say small project on the side, so are you building a kind of software as a service and things like that?

Markus:

Yeah. That as well. So trying out small products, basically, and and seeing whether they have whether they stick, I call it. So whether they have their place on Earth, so to speak. Sure.

Dominic:

That's great. This this is where I am as well. So we we might we might, pass a little bit of time here because, you know, it's not it's not a secret. This is my passion. I've been building Sass first since 2008.

Dominic:

Try still trying to find something that will sustain my family. I'm a little bit, in the same boat as you actually. Yeah. So, so yeah, this, this is great. So are you using Go to build, your side project?

Markus:

Yes. Definitely. I am. In fact, Go is the only language I'm using because I'm I've really cut down my stack as a solo developer. So I really like to keep things simple and choosing my tools wisely, basically.

Markus:

So that I can if I can cut things away and not context switch as much, then I can focus on being good at that one tool. And Go is one of those tools, definitely.

Dominic:

That's great. When, when did you discover it? So first first of all, have you have you started to program in Go directly in your career or, you know, you you had some, some some other languages that that you tried and things like that?

Markus:

Well, actually, I I went to Uber, in 2014. So that 10 that's 10 years ago, and we used Python a lot. But after 2 years of that and and some actually, both some JavaScript and some Dart, which is also a Google language. I came about this language called Go, which I thought was really weird at first, but I kinda it grew on me, I think. And then, yeah, I started using that, and now I'm using it exclusively.

Dominic:

That's interesting. So okay. That's great. What about, you know, let let's let's switch a little bit. So I I think we will we will do some back and forth between component and and and your current situation.

Dominic:

This is very interesting. Sure. So I I I first saw well, well, first of all, let's let's address the elephant in the room. Congratulation on the v one. I I just saw just before we, we started the podcast.

Dominic:

I just saw your your, your Reddit thread actually this this week. Oh, yeah.

Markus:

Yeah. Yeah. I thought I'd get it out before we were recording. So it's been going on for a while. So, basically, it's my I want to signal that components is stable.

Markus:

So I've been working on it for 4 years. And, yeah, that's something that people can rely on and that they can rely on it not breaking. So I don't wanna do any breaking changes if I can get away with it.

Dominic:

Yeah. That's great. I mean, this yeah. This this is a great signal for sure. Congrat congratulation on that form.

Dominic:

Thank you. So I I've I've seen Gunponent, and and I will be completely honest. I'm always honest in this podcast. I know that I I received the guy from Encore at some point. And, you know, I just say what I have in my mind.

Dominic:

When I saw Gunponent, I find it extremely interesting, but I was I was blocked by the fact that, oh, no, man. You know, writing HTML in Go files

Markus:

Yeah.

Dominic:

It seems to be I don't know. And I interviewed Adrian from Temple 2 or 3 weeks ago. I don't recall. So Yeah. After after the call, I was extremely excited about Temple, but unfortunately, it did not really work for me.

Dominic:

I I talked about that in the last episode. So when I reached out, I I started to to check at Gunpon and and start to, you know, pass. Yeah. Just just, you know, don't don't let me being stopped by the fact that, yes, you are kind of writing HTML in Go. This this is kind of a I would I would not say a DSL, but ish.

Dominic:

Yeah.

Markus:

Very DSL like, I think.

Dominic:

Yeah. So I I think once you once you pass that first initial thought, which I I can I might imagine, you know, a lot of people might have, it seems to be extremely interesting?

Markus:

Yeah. At least I think so too, in my humble opinion. So but let me maybe I should tell you about sort of the origin story for this. Sure. Sure.

Markus:

Because so I was writing a lot of React and React. Yeah. I was a full stack developer, basically, and writing a lot of React and and Go on the back end. And once I went solo, I really missed that. But I've I kinda wanted to cut out JavaScript because of, well, a lot of things, actually.

Markus:

But I I really missed that aspect of it, that building components in a go like thing. So, of course, I started with the HTML template from the standard library, which was okay. I think you can you can do a lot of stuff in that. Mhmm. What I didn't like was, passing data around.

Markus:

So it became cumbersome really quickly, I think, because you couldn't build new what in Reactline is called properties. So these props that you can't pass in a good way I think inside these templates. So you can't build new ones inside the components and parts passing to sub components. You basically have to have this global huge struct thing that you pass to all components if you want to do something like that, I think. Maybe that's a better way.

Markus:

I couldn't find it. I know I was I was really frustrated with that. And then I just got this idea, okay, can we build this in in Go directly? And I think at the so this was in September 2000. So it's, yeah, 4 years ago.

Markus:

So the details escaped me. But, it was something yeah. I wanted to I wanted to build HTML components in Go, and I couldn't find anything that did something similar. So I think this was before Temple, and I've since found a few libraries that did something kinda similar. But, yeah, I I got a prototype up and running pretty quickly.

Markus:

Sort of an spent an evening on it. Kinda liked it. Went through quite a few iterations of finding the right API. So I wanted it to feel good. I wanted to feel good using it.

Markus:

And then, actually, I listened to an episode of GoTime, the other Go podcast, and they talked about things that they didn't want to include. If they could take something out, what would it be? And one of them mentioned dot imports, and I thought, what's that? I hadn't come across that before. And I looked it up, and, oh, you can just import all identifiers from the foreign package into your own and then use it without package prefixes.

Markus:

And I thought, woah, this is great because then basically you can skip all the package prefixes for, yeah, in components case it would be HTML. Span or whatever and you can just write span and whoops now you have a DSL like thing like you said and I really liked that way of building HTML and once you get used to the whole okay there's no end tag with a name on it and it's kind of weird, but it's also kind of fun and and really productive in that way. And because it's just Go everything, you don't have a a built step. It's just Go functions all the way And and it started to really become, yeah, something nice to work with. And I I worked with it more and more and refined it, and people started noticing it and contributing to it.

Markus:

And I've started yeah. We started discussing it on GitHub and stuff like that. So it's really become refined over the years. So after these 4 years now, I think it's it's in a really good state, actually.

Dominic:

Very interesting. So, yeah, I'm I'm not a fan of that import for anything other than component of course.

Markus:

Not me either for the record.

Dominic:

Yeah. Especially especially as a as a blind person, you know? It it that that's one way I I I also talk at Go Time at some point why I I was thinking that Go is is, in my opinion, one of the more accessible, languages are there that I've tried. You know, I have not tried all the languages, but

Markus:

Yeah.

Dominic:

And and dot import is is is, you know, generally the only thing that I I can, you know, I cannot I cannot say that it's very helpful. In your case, it is because I mean, we we've all known HTML for so many years and things like that. So when we see div, yeah, it's clear it's clear that it's a div span and and whatnot.

Markus:

Yeah. Exactly.

Dominic:

Yeah. That that's interesting. So so yes, I I hear you all as well about the how to how to have component in the HTML, package, the standard library template. You usually have to, you know, to create a func map with with maybe a function called a map and pass and pass some, you know, some of the sub, sub fields of of your main struct and things like that. But, yes, it's, it's not as as pretty as as creating component for sure.

Markus:

And also, I mean, now probably the editor support is there so you can move around quickly, especially if you call it like, I work on the JetBrains platform. So if you call it .go HTML, then it can figure out that it's it's a Go template and you can sort of navigate it with ID help. I don't think that was available 4 years ago. So it's definitely become easy as well, I would say. But, what I would like about doing it in Pureco is that if well, that's the the Go, please, language server, and it just supports it natively, basically.

Markus:

So you can you can work around as you usually do in your Go code. You can use the debugger, if you need that for some reason. And so all the tooling is there already for you. I've just started looking at building my own language server just to see if I can get that sort of, for example, syntax highlighting that in different colors that is available in in my IDE for HTML that isn't for Go. But it's sort of more of a nice to have than a must have because a lot of the tooling is already there.

Dominic:

Interesting. Yeah. Yeah. That that's the that's a that's also a dangerous place to be potentially because now if if you are introducing some some latency and things like that. But but if it's just for coloring, I I I you know, I I could imagine that might be quick, but, but yes.

Dominic:

That that was, that was something, with my current machine and temple, the compilation, and also the the formatting. I mean, the again, I'm I'm a I'm a blind developer. So I I there's a lot of things that might apply to my situation that might not apply to everyone else, but the for the formatting for me is also another reason why I'll have Go. Why I also, you know, look at Gunpone and then and says, this this is pretty interesting because now it's the, you know, probably the the the Go standard formatting that is that is formatting all the function function calls and and whatnot. So, I mean, this is more of an advantage.

Dominic:

Yeah.

Markus:

Yeah. Yeah. And you have all the I mean, in in a templating language, you have to, basically design all these controls structures around that you can then use in the 10 like like conditionals and looping and all that. And here, it's yeah. It's because it's just code.

Markus:

It's built in and you know it already. So it's not a different kind of syntax you have to learn. Yeah. Absolutely.

Dominic:

That that's, that's great. So so so before the dot import so I I guess you were experimenting with with having a the smallest package name possible, something like, I don't know, HTML or something like that, maybe?

Markus:

Yeah. Exactly. But you you can call it anything because you can just prefix the import with with whatever package alias you want to use and you can use that. But, yeah, I wanted it short definitely. So one letter ones is is preferable.

Markus:

And I still do that sometimes because there are different packages in the components module. So we have the call module which is just the rendering function basically and the call interface called Node and a few helpers like inline conditionals and mapping and that sort of stuff. And then I have the HTML package which is all the HTML helpers. So those are the yeah, the basically the elements and the attributes that exist in HTML. Molly has everything.

Markus:

I always miss some and but someone comes along and says, hey. I need this. Okay. And we can merge it in. Right.

Markus:

Then I have just 2 helpers actually. 1 is to write the the document structure for HTML 5, which is yeah. One of them and the other is something I borrowed from React land which is just the classes helper which is just conditionally applying CSS classes to an element basically. But those are the sort of the core packages so so you can prefix those. I actually started to just dot import those as well because it's yeah then it again it looks very DSL like and if I keep it to just my HTML package in my application, then I think that's fine.

Dominic:

Right. I guess the node, for example, I I guess the the node is something that you are passing. You you might be passing that a lot. I I guess when you are treating layouts and in in, you know, component that that should render into that layouts, you you expect some node to be passed to to function.

Markus:

Yeah. Exactly. So all basically, all things in components have to do with this node interface and it's very much it's a very simple one just like in in temple actually. So it's called, it's called node but it has just one function which is render which takes an IO writer and returns an error and that's it. So if your component satisfies that interface, then you're good, and you can you can plug into the whole component's ecosystem.

Markus:

So every HTML element and attribute in the in the library satisfies that interface, but it's very easy to create your own components. So what I do is to usually just have a function in in an HTML package of my own in in the application, and then that function returns a node, and then I just return start return diff and then my whole component tree and pass in the data and whatnot.

Dominic:

So is yeah. I have a might be a weird question, but let's say

Markus:

Bring it on.

Dominic:

Is is the is the top level function going to receive a lot of data? Because let's imagine let's imagine we are building something very simple. We will have a current user. We are building a to do list, for example. That that's an easy example.

Dominic:

So when you are on your, you know, HTTP handlers, you will you will call the function with which represent the top level layout. And this layout should should, you know, receive everything that all the component in that page will will need. Yes. Basically. So what what you know, how are you doing that as as someone that is that is using your your library a lot?

Dominic:

You know, do you do you create structure that you you just pass this structure and and and from calling this sub component in the layout, you you are only passing a parameters at some point or you are keeping structure all the way and things like that? How are you doing that?

Markus:

I usually have one, let's call it global, properties. So I think I call it page props most of the time, which is the things I always need for every every page, basically. So the title, the description for for the HTML page, but also stuff like, is there any user authenticated? So set that. Also pass request context perhaps so you can you can do a cancellation if you need that.

Markus:

Yeah. But having having this one global struct that every page gets that I can rely on, then I can do global stuff like showing the header on a page, for example, the navigation bar, figuring out where am I on what page am I currently and and stuff like that. So if I think something is applicable to all pages, then I put it in that. But otherwise, I actually keep it as function parameters to that individual page because I like the explicitness of seeing, okay, what kind of data does this page depend on? And then that makes it so I don't actually use testing a lot for my HTML components.

Markus:

But if I would do that, then it would make it very easy to pass in the data that I want to display and then make sure that it displays it in the right way. Interesting.

Dominic:

So this, this global page, page structure, you I I guess you are receiving let's say let's say you have a layout called whatever, main page or root or or whatever. This is the name of the function. So you would you would technically receive 2 parameters for that that function, your global page object and also the list of to dos for for that page, for example, in a to do application.

Markus:

Yeah. Exactly. So you would you would take a slice of whatever model you have to do, and then you can, yeah, display that, in this declarative fashion that we also know from from React.

Dominic:

Interesting. Yeah. What is, what is the group, object or functions? I I I I was not not sure about that one. Did, you know, the the if I understand and but

Markus:

Yeah.

Dominic:

Yeah. The group, I'm I'm not sure.

Markus:

So, basically, it was something I needed, in conjunction with the map. So map was something I implemented before. Generics was a thing. I think it wasn't I started the project when it was go 115, I

Dominic:

think,

Markus:

where we didn't have generics. And I wanted something to easily map my data to components, basically. And so I added the map function, but because I couldn't render it directly, I needed to sort of group it. So there would be something that could satisfy the node interface and then be injected directly into my components. Yeah, and that's basically what it was.

Markus:

So it it's it's actually one of the things that was changed recently. So instead of being a function it is now a slice type. So a group is just defined as a slice of nodes and it can render directly so it's certified node itself. So that means that you can now just call map and then on your data and your then you have your callback functions through the mapping and that result actually returns a group directly and then that you can just put it into your component whereby it accepts a note. Got it.

Markus:

Yeah. Interesting. And then we yeah. So basically so it also for a lot of people using HMX, they often want to render a yeah. Basically a list of nodes, but having a nice syntax for it.

Markus:

And group enables that as well without having a pairing component.

Dominic:

Interesting. Yeah. Spe speaking of HTMLX, you know, how how would you how would you add the, the the h x attributes and and things like that on on, you know, elements that are not really HTML element at the end of the day?

Markus:

Yeah. Well, they are HTML attributes, actually. And I I actually have a components dash HTML library as well to show off this kind of functionality because it's also something I use in my own projects. What I usually do is import this module with the hx prefix and then it has all kinds of helpers inside the library that also satisfy the node interface. So if you've got that imported, then on your input component, then you can do hx.

Markus:

Post and then give it the, yeah, the attribute value as you usually would in a string. And then it just works like that.

Dominic:

Because the attributes are variadic parameters?

Markus:

Yes. Exactly. So in basically, all, all elements that can accept children have variadic, yeah, have a right variadic node, slice at the end. I don't know what it what that's called, but

Dominic:

Okay.

Markus:

Yeah. So so for example, you have the div and then, there's nothing in the helper that is specific to div. It's just okay. You can now give it 0 to many nodes, as children, and it'll just render those, basically.

Dominic:

And if one of those nodes is is an attribute, it will it will not render that into the into its content. It will it will be

Markus:

Yeah. Exactly. So it does a 2 pass render internally, actually. So it, yeah, first, it writes out the name of whatever parent component we're using, parent element, I guess. And then does it pass recursively, to check whether there are any attributes?

Markus:

Mhmm. Because recursively because we can have groups as well. And then you've write out the attributes. Basically, I check all your children. Then you check all your children again, write out the elements, those node that, element type, I call it, and then finish off the the element by, yeah, writing the closing tag, and that's it.

Dominic:

Interesting. So do you do you discipline yourself then? Because correct me if I'm not understanding correctly, but that that that would means that I could have inside a div a first parameter that would be an attribute. The second one could be the child itself. And after that, another attribute?

Markus:

Yeah. You can definitely lose that. I wouldn't recommend it.

Dominic:

No. No. But but it's possible. Right?

Markus:

Yeah. But in general, actually, that that's a good point in general because I'm I'm not doing any validation on whether you're writing good HTML. So you can do all kinds of weird stuff. So the only thing that's guaranteed, which I guess writing raw HTML doesn't do, is that the int tags are written in the in the correct place because you can't you can't, like, do diff span diff and span end like you couldn't s HTML because it's a function call. So write that naturally.

Markus:

But otherwise, yeah, I'm not I'm not doing any validation on the HTML at all and and that's very much by design because I don't want to open that kind of worms that is HTML validation. I'll leave that up to the browsers basically and other tools. Yeah.

Dominic:

Yeah. So what what about, let's say, Alpine JS? What about if I would want to to write any kind of things to to this, to this element itself? Do I do I have a way to pass, I don't know, a map of a string string potentially that would go directly as is in the attribute, list for that element?

Markus:

So I do you mean passing data to to JavaScript?

Dominic:

Well well, it's it's not really JavaScript. So, you know, and I'll find let's say we have a button. I could have a at click equal and and do something. Let's say set a set the variable to true, for example. Or or let's say we have a drop down.

Dominic:

So when you when you have a drop down, you have a button which is the trigger, and there's an attribute in HTML which is the, the at sign with with click. And that that tells Alpine to register a click event for that button, for example.

Markus:

Okay. Yeah. I've never used Alpine, but I think I I I get it. Yeah. You would probably have your own components that have these, like like a click attribute, for example, which name is at click, and and the value is whatever you provided.

Markus:

So I don't do any, validation on the attribute values. Apart from that, you can't break out of the attribute value scope. So basically, check that you can't write a, yeah, something that breaks out of that scope. So I take that directly from the HTML, package template package in the standard library.

Dominic:

Nice.

Markus:

But otherwise, you can you can write JavaScript. And by the way, you can also inject raw strings. So I've got a raw function where you can write whatever because, essentially, what components is is a glorified string builder. So in the standard component, elements, when you write those and make sure that it's valid HTML and it escapes the right characters if you need to. But you can also inject them with raw and then you can write anything.

Markus:

So if you need to put in CSS inline or JavaScript inline, you can do it that way.

Dominic:

Nice. Have you have you done any kind of benchmarking? Because I suppose that, let's say we are building a, you know, decently sized UI application. We will have a lot of functions called. Have you done any kind of benchmark between a an HTML template versus, component because each time that the page is requesting that that an handler is running, we are rerunning all of those things.

Markus:

Yeah. Exactly. I would say yes and no. Yes because, yeah, I've I've done some benchmarking to see that things are not totally off. What I haven't done is extensive testing on how it behaves.

Markus:

I mean, I've been running components in in production on my sites for several years and never hit any issues, even when hitting the front page of Hacker News. So I have great trust in that its works, but I haven't done a one to one comparison to to build the exact same HTML pages and say, yeah, standard library HTML template, temple, and and components, for example. The reason is that I know this is all just function calling underneath, and we're writing through the IO writer. And I know that's that's not really anywhere where I see a lot of problems. Maybe maybe it could still happen, of course.

Markus:

So especially with respect to maybe there are a lot of allocations and the garbage collector has to work really hard. I haven't seen those problems myself, myself. But I've been thinking recently actually about, yeah, building a sort of a big document structure and then doing the benchmarking and and tweaking a few things and then seeing if it has any sort of, yeah, if anything changes, if it if it has any, what's it called? A missing word here.

Dominic:

Performance Consequences.

Markus:

Yeah. Yeah. Yeah. The word. Yeah.

Markus:

Is there any consequences?

Dominic:

Yeah. It's it seems to be extremely, extremely quick. I'm I'm I'm just I I was just curious about that. But Yeah.

Markus:

Yeah. Understandably. And you're not you're not the first to mention it. But I think also it's important to keep in mind where are the bottlenecks in a typical application in a web application. Oh, yeah.

Markus:

Totally. And it's often I mean, you have to talk to the database probably a few round trips anyway, and that's probably over the network and also your users over the network. So compared to that, components is pretty insignificant. So it's only I would worry start worrying if this became a problem on, for example, memory allocation or something like that. Right.

Markus:

Where you can't have many concurrent connections because your server will run out of memory. That I would consider to be a bug and I would start looking at that if something to be improved there. But otherwise, I I'm fairly confident that that it's in a good state.

Dominic:

Nice. Speaking of database, what what are you using in your side project? Do you use SQL C for example?

Markus:

I do a lot of SQLite. I'm actually a big fan of it. So I I like Postgres if if the project requires something that, has a lot of data manipulation. But for the usual CRUD app, I really like SQLite. Now you can

Dominic:

Do you use the the the the c driver or you're using the, the Go,

Markus:

the the packaging The transpilation one. No, actually I use the C driver. Nice. I think it works nicely. So what I like about SQLite is that it is so extremely well tested because it runs on so many devices and I have total confidence in the in the original C stack and I like including that directly.

Markus:

So there's no possibility of introducing bugs because of the transpilation basically.

Dominic:

Nice. And you're you're writing your the, you know, all all the the rows and the scans and and whatnot yourself?

Markus:

No. I've got abstractions on top of that. So there's this nice library called SQLX. I don't know if you know it.

Dominic:

Yeah.

Markus:

Yeah. Yeah. Which basically does everything I need, I think. So I'm a big proponent of writing the SQL queries myself. So I don't use any arms.

Markus:

I don't use SQL c, although it looks interesting as well. Oh, yeah. I just like being able to write the queries as I need them to because I think that's very expressive and and just the easiest way for me to think about what I want out of this. So I'm I'm so used to SQL, and all tools in the world basically speak SQL if they can do anything with data. So it's it's just so extremely easy.

Markus:

And then in combination with SQLite, we just copy this one database file around and you can Yeah. Debug production by copying the database locally if you want to. And it just a combination of being able to do that to to write the same SQL in in your whatever GUI edits that you have that you do in your application code. And I think that that combination is just glorious.

Dominic:

Nice. So So have have you used, a lot of other stack in terms of of views and whatnot? So I'm thinking maybe Django or Ruby on Rails and things like that. So I I know I know that you were inspired by React, but but was there anything else that that when you when you are when you started to use the HTML package, the template you you were saying, well, I'm I'm missing a lot of stuff. Not not really only things that relates to React or or it was 100%, you know, you were missing the creation of component in in React, for instance.

Markus:

So do you mean do you mean sort of extras that are nice to have when building web applications? Or

Dominic:

Well, yeah. I mean, the, the views in Django and and in Rails are are, you know, way more advanced than what we have in in the basic HTML templates. So I I I will I was I was wondering if if that that would that would have had any kind of impact on on your decision to want to build component or it was 100% based on on you wanting to maybe ditch, React and and just just having everything in Go, for example.

Markus:

That was actually pretty much it, because when I when I wrote a lot of Python, I didn't write any UI code at all. There was some back end.

Dominic:

Okay. Okay.

Markus:

Yeah. So I I don't actually know that well. I know Django is very known for being easy to work with and getting something out quickly that way. But I felt I had the same thing in React also because it's the really, really great thing about React is the huge ecosystem. So everyone knows it, and you kinda know how components work.

Markus:

And even though there have been some weird changes and and I think it's become more complex over time, it's still at its base. It's very easy to comprehend. And I think that was the main thing missing for me. So when when I first started out with, yeah, standard library HTML template, I thought it was hard to figure out how you exactly are supposed to load the templates into your application code and then you have to name them to be able to include them in blocks. But you have 2 different ways of including the blocks.

Markus:

1 is, it does something if it's not defined already and and another if it's defined and I don't know it it it got surprisingly complex quickly, I think. Yeah. And and it's not that React isn't complex. It definitely is. But the the mental model of it is very easy, I think.

Markus:

And then that's also one of the things I wanted to replicate to not have this mental overhead when when switching yeah, when building new projects and then and switching between writing back end code and front end code that it's just easy to map go back into that world and okay, now now I need to write UI and and how do I do that and just have this mental model that's really, really easy. And just having these functions as a top level thing where you can just dive in like you do in regular function and then see what's going on, I think, yeah, that was the big inspiration. And then, of course, how you pass data around and then do it in this declarative fashion is definitely something I've taken from React so that you have instead of having for loops, you have this mapping operator instead. Yeah. And I I really like that.

Markus:

And that that's only become easier since generics became a thing. So you can have, yeah, basically all that, yeah, when you're using components as well.

Dominic:

Yeah. Yeah. Totally. Can can you, walk us a little bit? Let's say let's say you are starting a new side project, for example, today.

Dominic:

Yeah. So well, of course, you are using component. I'm I'm I'm interesting I'm I'm interested to know what is your structure? First of all, you know, are you always creating, like, I don't know, a views package and what will be inside that package? And also, if you were to pass some structure to your to your your function, your view functions, you know, where are those structure are defined for example?

Markus:

Right. Yeah. So I've started moving things into my own little web framework. So I have some inversion of control because writing the same thing 20 times gets gets old. But but if I didn't have that, which until recently I didn't, it would be a sort of a command, main thing where where all the setup code is and where you set up your dependencies.

Markus:

And then an HTML package. No. Sorry. HTTP package, which has the HTTP server and has the routes defined as well as the HTTP handlers.

Dominic:

Mhmm.

Markus:

And then an HTML package, which has all the views inside them. I've ripped this from Ben Johnson, who's also a Go developer and did, who's done LightFS and LightStream for for SQLite. He I think he had a blog post somewhere. I think it was him. He had a blog post about how he structured projects.

Markus:

And I thought it just really made sense because it kind of replicates the standard library as well. So if you need something HTTP like, you look into the net HTTP package. Of course, yeah. And if it needs something HTML like, you look into that template HTML as well. I can never remember which way it is.

Markus:

HTML template or template HTML. I think it's template HTML. Yeah. But basically so so I structured it that way so that when in my glue code, which is either in the command itself or some package called service, I can say SQL dot database or new database, and then I get the database abstraction back, which is basically a wrap up around, the standard library SQL. Mhmm.

Markus:

The same with my HTTP dot server, which is just a wrap up at the standard library, HTTP server. But because everything HTTP from the standard library is encapsulated in my own HTTP package, then all the glue code only has to know know about my own packages and nothing from the standard library. So if I have if I have to import something HTTP like from the standard library, then basically I have a leaky abstraction and I should fix that.

Dominic:

Interesting. And then inside your HTML package, are you creating sub packages in there, or or it's like a flat,

Markus:

flat? Actually very flat. Yeah. Interesting. So I have the only exported functions are my pages and sometimes my partials if I'm doing the HTMLX.

Markus:

So basically parts of a page which is what I call partials. Yeah. But those are the pages and they have some a lot of common components, which are not exported outside the package except if I need to test them, but I usually don't for HTML. Yeah. And that's basically it.

Markus:

And, of course, you can subdivide in different files and you can because it's Go, you can easily move things around from file to file. And so I usually start in one big file. And if the need arises, I split it up, basically. And and so using Go because it's on the package level that everything is called from outside, so refactoring is easy that way.

Dominic:

Right. Interesting. What what are yeah. This, this, this is this is great. I I will need to to try that for sure.

Dominic:

But, again, it's nice. It's tempo and component seems to be way easier when you're starting out. Yeah. I I'm I'm already, like, 4 months in a SaaS that I'm building with my wife, actually.

Markus:

Alright.

Dominic:

I will I would love I would love to adapt something else than the HTML template. Yeah. Because yes. I mean, I I I created my my own small, helper library to to do with with parsing the templates and having partials and whatnot. But it's not component for sure.

Dominic:

It's Mhmm. And, one thing that you just said that that makes me because I'm a huge HTMLX user.

Markus:

Right.

Dominic:

I I can see myself having a component. Let let let's let's continue with our to do list example. Let's say let's say that we have a a to do list. That that that is the function that, you know, receive a slice of to do and just just, I don't know, prints prints a div and inside there, there's a map to to go over all all the to do and and just render them. Yeah.

Dominic:

So in in HTMLX, I could I could just call this, this this small function directly and just just pass the, the, HTTP, response writer directly and and that's it. I mean, this this compared to what I am doing now with the HTML package, which I I needed to create a completely blank raw h t I I call it raw dot HTML. This is my layout, which has nothing in there, other than than the block that something will will will fill in at some point. But this is, it it seems to be way cleaner with component. And and I will I will not have to, to create a lot of files that that do have the same name that, you know, take care of rendering the the thing when when when it's not HTMLX and when it is HTMLX that do a post and I need to return this famous blog list, function or component.

Dominic:

Yeah. In my case, I I have 2 path for that. But in component that that that's just one function calls. This is this is beautiful.

Markus:

Yeah. And these you can structure it that way. I would say because, yeah, I'm also using HTML sometimes. What I do a lot is inspect the request headers and then check whether it's an HTML request and then return the partials based on that. So I I think you could do basically the same with the HTML template.

Markus:

But, yeah, you have to take care how exactly you are defining your templates and and which blocks. So I would have to see it to make sure.

Dominic:

No. No. Sure.

Markus:

The way I envision it, at least, I can see it, is that yeah. It would it would kind of be the same, but for me at least, it's more transparent to figure out what's going on when it's components. Again, because it's in the ID and I can click around and and and basically follow paths until I figure out what's going on. And what I would usually do in this case for yeah. With the to do example for example, is have some kind of partials for those that, those small like a to do item for example.

Markus:

Let's let's say you want to add that and you have an input box or whatever and you you add it to do it. You push enter and then you want something to happen on screen to make that to do added to the list. Mhmm. So I think what I would do there is yeah. HDMax basically calls the back end and the back end, returns this one to do item component that you have anyway.

Markus:

So you would have that exported in your HTML package and then you could do the swapping in the DOM through HTMLX but the point being that you use the exact same function code when you're first doing the full page refresh because your page layout is also just using that partial And then when you're doing the subsequent calls through HMX, then you would you just return that partial. And and yeah.

Dominic:

Yeah. I really like that. You know, that this this is this is what I was trying to say exactly. This is what I had in my mind that that that and to me, compared to what I have at this moment, which is not terrible in the HTML template package, but again, there's a lot of there's a lot of repetition in in files and whatnot because just the way of how I I did things. And sometimes yeah.

Dominic:

It's when you realize that it might be better, but it's it's already too late about that. So that that's another point. How would you approach someone that would want to try component and and try to insert, insert it into an existing project?

Markus:

Right. I think for what I first would do is figure out if it's an existing explication, figure out one small part that gives you some pain in the way you're doing it right now and then you would try components on. Mhmm. Yeah. So basically, you get the module, and you can start off really stupid in a way by just calling dot raw, components dot raw and then injecting your your strings for the things that you don't need interactiveness on.

Markus:

So don't convert all your HTML code to components immediately, but just call this raw thing. And then where you want something that's more intelligent, you use the components code and you build your your components, basically. And then, yeah, try it out with that one small thing and then see how it feels. I haven't actually tried mixing HTML template and components, so I don't know how that what what that's like, basically. But I've tried with raw HTML that I've gotten from elsewhere.

Markus:

So for example, UI libraries and stuff like that. Well, I don't want to necessarily convert all my HTML to components because it's just static anyway and doesn't necessarily make a lot of sense to to convert that because you're not getting that much for it basically for your work. Yeah. Yes. I think that's what I would do.

Markus:

So isolate one small thing, try it out, prototype your way out of it, and try it out and see how it feels and see if you like it, and then go from there, basically. Cool.

Dominic:

And, let let's return quickly to, to the the class helper that that you were mentioning. So I assume that it it's probably something like a map string, bull, where yeah. So what what about some things like I don't know. Let's let's let's say Tailwind because everyone is using it. I'm already tired of it.

Dominic:

Yeah.

Markus:

Myself included.

Dominic:

Yeah. I've I've I've I've been using it for a long time. And, yeah. It's it seems like when once everyone is using a CSS framework, I I get I get tired of it. But but it's it's still pretty pretty great.

Dominic:

I It's

Markus:

a it's a new inline styling. I like it. Yeah.

Dominic:

But don't you don't you have, like, so many line that that fill out your map if you are using well, may maybe maybe maybe not using this helper, but but just having all of those CSS classes in Go, I don't know. It seems, is it is it as easy to edit as as the HTML view, for example? You know, when when you are on your editor. Mhmm. I I I do I do use, Prettier, a lot, to be frank.

Dominic:

So so it's really it's really helped with I don't know. You know, just just adding, one attribute on each line and and okay. I'm I'm on the class attribute. I I know that I'm on tailwind. It will be like a a miles long, or one Yeah.

Dominic:

One kilometer long, thing. So how is it how is it, translate to in in component?

Markus:

Well, you can do it in different ways. So I have this, as you mentioned, the classes helper, which is, yeah, string to bull map. So if it's true if the value is true, you include it. Otherwise, you don't. So I don't use it that often actually, because often what you really need is 2 different components that are styled differently.

Markus:

So that leaves me with just a regular class attribute with a long list of space separated strings. So, yeah, that doesn't get pretty end components than it does in HTML. Yeah. Unfortunately, I add line breaks and try to add some structure. But, no, I wouldn't call it pretty, but it definitely gets the job done, and it makes it much better than I could do myself in CSS.

Markus:

And I'm basically never writing CSS anymore.

Dominic:

Right.

Markus:

It's all Tailwind and using InkComponents because the 2 just fit so well together. I like Adam Wasser from from Tailwind CSS. He had this nice blog post ages ago about how he really stumbled upon Tailwind CSS because he couldn't figure out naming all the things and in CSS and you don't have to in this way because you just have the components and then you have these inline styles. Yeah, they have really tightly coupled in a good way. And So, yeah, it's it's not perfect, but I don't think there is any perfect solution.

Markus:

It's all trade offs all the way down. And I think, yeah, looking at these long space separated strings is is the pain you have for basically easily being able to build, pretty components. Yeah. Yeah. Yeah.

Dominic:

Oh, no. No. Yeah. I I'm with you on that. It's just that

Markus:

But, yeah, it's not better than HTML. No. Yeah.

Dominic:

It's just that when you have a screen reader, I'm having a

Markus:

Oh, yeah. You

Dominic:

know, 30, 30 things that are read to you, it's extremely, extremely painful.

Markus:

Yeah. I can imagine. Yeah. I don't know if if tooling would make that belcher. So basically, if you can skip some of that or Yeah.

Markus:

I

Dominic:

don't know. Yeah. Usually, you you just you just go to the next line as quickly as possible because

Markus:

Yeah. Yeah. Yeah. So, of course, you can if you're in components because it's again, it's just go, and you can you can put it on separate lines and stuff. So what I often do is have the class attribute on a line on itself so I can visually just remove that either by well you could of course totally make your edits to do that so collapse the thing and you don't have to look at it anymore when you're not working on styling and you can just work on functionality.

Markus:

Otherwise, at least Yeah. So I don't know if you can get your screen reader to jump that line or something like that, but that would be the equivalent. Right? Right. Right.

Markus:

And then you would have all the elements in the component that semantically do something with your data, and you can focus on those instead.

Dominic:

Yeah. That's interesting. Are you are you creating a lot of components? Are you are you, like I don't know. Let's say you want you know that you will be reusing a lot of input all over the place.

Dominic:

So are you creating a component called, I don't know, the standard input and and this is this is where you you will use that same for a button, for example, instead of rebooting yourself all over the place. Can you, how would you approach how do you know when you need to create a component or not?

Markus:

Yeah. When I'm when I find myself typing the same things over and over again, that's usually a sign I need to do it. And I think it's very much the same as when you're writing the same code that does the same thing, which has nothing to do with HTML. So in Go, it's very much, yeah, copy a little, that's fine. If you're doing 3 or more times and it's exactly the same then it's probably time to refactor and pull it out into a function.

Markus:

And that that's exactly the same here. So if I'm doing it once I write I'm doing a button. Okay. Now I'm just leaving it like that. If I'm doing it again, okay, I'll actually I'll just leave it too because yeah, they're the same and I just copied it, but I'm not exactly sure that they're exactly the same yet.

Markus:

And maybe I want to change a few yeah. Tier one CSS classes, for example. But when I'm doing it the 3rd time, I would usually go, okay. Now I'm tired of writing it. I'm going to pull it out into a function that creates a component and, yeah, isolate the variable stuff and and make those parameters, etcetera.

Dominic:

This is this is where I I was thinking earlier when I when I was wondering if you were creating some some kind of sub packages. I would I would imagine myself creating sub packages that would not be exported. Well, the yeah. They they would need to be, but I they would they would never never be called, from the handlers, of course. So it's No.

Dominic:

You know? Yeah. They they would just be, like, helpers and things like that.

Markus:

Yeah. And what I've started doing is pulling it into my own little web framework. So it's Oh. And then very much because I want to my aim is to build a lot of different products and try them out because I'm bad at market research. So I just want to I want to be able to build things quickly and try them out instead of thinking endlessly about whether it's a good idea or not.

Markus:

So because I think luck is a big part of all this. So, so, yeah, basically what I'm doing is pulling these out into my web framework where I have this HTML package as well with all the components I'm usually using that are more high level than than HTMLs themselves. And that's basically what you would find in your usual component library like the yeah. The buttons and the input boxes and, maybe the forms and the sign sign up stuff and yeah. List the list goes on.

Markus:

Yeah. Yeah.

Dominic:

I I I think having a library already done I I am I mistaken? But there's already there's already, a couple of that that that are done for, I think, Bulma, if if I'm not mistaken.

Markus:

Yes. There's a few people who have done. Yeah. Balmain CSS, which I actually used back in the day too. I think a lot of people are still using it.

Markus:

Yeah. Someone made a component thing for that. A lot of icons as well. So I did one myself called Hero Icons, but there's also Iconify and I forget the name of the last one. Let me just check.

Markus:

I have it right here. Oh, yeah. It was Lucid icons. Mhmm. Right.

Markus:

Yeah. Because it lends itself easily to being extensible because it's just this one interface. And if you satisfy that, then you can include it in the component ecosystem.

Dominic:

I would I would assume having, you know, using a package, let's say, Hero icon, for example. I I want, I don't know, the the chevron down or whatever. It's it's way better to call that the, I think, the SVG with the path in line.

Markus:

Yeah. Yeah. Exactly.

Dominic:

Yeah.

Markus:

But it and it ties together nicely, I think. So I I actually had SVG support, in components, but I I removed it before the version 1 release because I found that it rarely made sense to have, like the the SVG elements like path and group and whatnot to have those available as a Go function versus just having the SVG top level element and then just passing a raw string in, basically. Because the SVGs don't they don't mutate based on state you pass into them. They're always the same. You probably change size and color and stuff like that based on, in my case, tailwind CSS.

Markus:

So I just put classes on it and and call it a day.

Dominic:

Right.

Markus:

And I didn't want to support that basically. So I took most of it out. Now I have the SVG top level element and the rest is gone. And you can either include it through with embedding for example, so embedding SVG files and then putting them in strings or or just putting in string literals.

Dominic:

Is the is the the final HTML that is output, is it is it any kind of, I don't know, minified or or is it is it different than what the structure is in Go, for example?

Markus:

No. Because components is a clarified string builder. So it puts in the strings into the IO writer and that's it. And it doesn't do any post processing. And again, that's intentional.

Markus:

So using something like Prettier for example is something a lot of people do and yeah, you can do that. But by default, it doesn't even put in new lines. So it just spits out this huge long line of HTML. So I guess you could call that minified by default.

Dominic:

Alright. Okay. Okay. So so there's no there's no line feed anywhere in there?

Markus:

No. Not unless you put one in yourself.

Dominic:

Yeah. Yeah. Yeah. Okay. That's good.

Dominic:

That's good. That's good. So what what is what is the future for for gunpoint where, you know, we we've talked at the beginning. You you just announced the v one, which is extremely exciting. You know, what is coming next for for this package?

Markus:

Actually, I would say hopefully not a lot. Yeah. Because I I just like having this put this, very stable, mature module out that hopefully doesn't change a lot. Yeah. But what I would like is something that's more outside the modules.

Markus:

So if people start building components and sharing and and making more of an ecosystem like the one that's available in React, I don't have any intentions or hopes for for making it as big as React. I don't think we're going to we're going to succeed with that in Go land. But, yeah, having people share this a lot, actually like Temple. So Temple has really gone off in popularity and people are building out all kinds of stuff. And I've seen some of that, but not as much.

Markus:

And so and I guess it's also yeah. It's because some people refer the HTML syntax and really don't like like, really, really don't like the components, way of building things, and I think that's fine. And some people prefer the components way of doing it with, yeah, having pure go and no build step and all that. But but having people start building components and sharing them with each other and and sort of making it a nice way of of not having to reinvent every component every time you need to build a new project. I think that's that would be really cool.

Markus:

And I'm working on that myself. I want to start building more high level components and putting it inside this components gallery repo that I just made a few days ago. And what

Dominic:

is the backing CSS? Is it tailwind as well for that?

Markus:

I haven't quite figured that out yet, to be honest, because I'm not intentionally not doing anything that's bundling of any kind. So there's no CSS, no JavaScript bundling. And I'm not sure what the best way forward for that is because when I'm building apps myself, I have this Tailwind command line interface utility, which basically looks at all the Go files, pulls out the class strings and then, yeah.

Dominic:

Yeah. It

Markus:

builds a small CSS bundle based on that, right?

Dominic:

Yeah.

Markus:

I don't know how that would work with something that's exported elsewhere. So I I think right now that that's something that people would have to include themselves. Of course, you can make life easier by sharing configuration and all that, but I think that's actually something that the like the last step application would have to do. So look inside the modules and when building those pulling out the, yes, tailwind CSS classes and then including that in the top level CSS bundle.

Dominic:

But give us an example. So so what kind of component are you are you thinking of putting there, for example?

Markus:

Well, the I guess the usual stuff. So tables making that easier or buttons and all the things that you expect from a sort of a UI library. So I don't intend to build a UI library myself. Right.

Dominic:

Right. I

Markus:

just want to underline that. I'm not a very good designer or anything. But it's more than the stuff that I always use that I don't want to keep rewriting and could might as well share. So including favicons in your HTML template or open graph tags, Twitter cards. Right.

Markus:

Stuff like that as well, which is doesn't need any styling and it's very easy to just include like that. But I'm not sure how much of that there is that is really reusable. It also might just be that it's easier to take one of these and instead of including it as a module, you copy paste the component into your own code and then modify it as you need it. So I think that has a lot of value. And I think, what a lot of people are asking for is, well, how do I get started using this?

Markus:

And so it's not as much as reusing components as it is okay. What is a good structure of doing this? And for that, I have an example application inside the components library, but I also want to do a more full fledged. Okay. If you were to use components and HTML and Tailwind CSS and put it in a Docker container and deploy it to production somewhere, what would that look like?

Markus:

And I basically have that already. I just need to pull it out and put it into an example repo. Nice. Nice.

Dominic:

So and you you also have a Go course. Right?

Markus:

I do. Yes. Nice. Building cloud apps in in Go, it's called. Yeah.

Markus:

Well, actually, I use components also, a slightly older version, but that doesn't really matter because things have been pretty stable. But it's very much in the same what should I call it? Aesthetic. So I want to I'm teaching people to build Go web applications and put them in the cloud and then use the cloud building blocks that are available. So S3 object stores and postgres database and a stable queue, SQS in this case and how do I send out emails both marketing and transactional and sort of building a little basically the canvas for a tiny SaaS web app where you have newsletter sign up and authentication and also stuff like alerting and and metrics and logging and stuff like that.

Dominic:

Nice. So you you have a great domain name. I I wonder if the Go team will contact you at some point. Right?

Markus:

I don't think I have a trademark on this. I'm not sure that's possible, but yeah.

Dominic:

No. No. That was a joke.

Markus:

Yeah. But it's got golang.dk. Yeah. Exactly. For Denmark.

Dominic:

This is, this is interesting.

Markus:

I was quite surprised I could get it, but it was taken once before, but it it expired and I got it. Nice. I think that's quite nice.

Dominic:

So I guess I guess if people want to, to connect with you, that that's a good way. The the component website. We will we will have all the links in the show notes. So do you have a closing comment or thoughts? Is there anything, I don't know.

Dominic:

Anything missing in Go? Anything, anything that you would like to see or or just want to close on that?

Markus:

I think I want to close on a bit different. I'd like to just say people try try components. If you don't like it, perfectly okay. Understandable. It's weird at first.

Markus:

You can get through it, but start sharing stuff. I really like to see what people are building with this and and see if we can expand the ecosystem a bit so we can have, kind of what we have in React so we can start building applications faster.

Dominic:

Nice. And in my case, I will restate what I've said multiple times. Maybe it's just me, but if someone would create a dead easy UI, you know, like a kit or something that would just be there to create web application that is similar to what we have on the desktop, for example. I think I I would I would jump on that. This is Oh, yeah.

Dominic:

Yeah. For me, for me, I'm I'm kind of I've I've been building web applications since 2000. I mean, I've I've been Yeah. I have seen HTML 3. I've seen HTML 4.

Dominic:

And now we are HTML 5. Yeah. It's it's it's very nice. Don't get me wrong. But at some point, I'm a little bit fatigue about CSS and and things like that.

Dominic:

I just want a good looking, you know, thing. I I just want to put a button on on on on the place, not have to style it. It it it it just looks good. That that's all that's all I want.

Markus:

All I want for Christmas. Yeah.

Dominic:

Yeah. I I I might I might do that at some point, but but no, I wouldn't. Thank you, Marcus. It was it was great. I I will I will try it for sure.

Dominic:

Maybe, maybe we can, we can have a version 2 of this of this call a couple of months down the line and see how things are going.

Markus:

So And reach out if you hit any problems or have comments because I love hearing from people.

Dominic:

Sure. Sure. Thank you. Yeah. Well, I will try that.

Dominic:

Because to to be frank, I I I I was I was excited about Temple, but, yes, The the the tooling, was a little bit rough for me with my screen reader and things like that. So this this this is why maybe maybe component is more my my fit now because because, yes, I can rely entirely on on the Go tooling, which, you know, it's there. It's there for me.

Markus:

So Yeah. Let let me know how that goes. I'd be very interested in that.

Dominic:

Absolutely. Thank you. Thank you very much. And and I encourage everyone to check your cars and check your Go component. It's a great project.

Markus:

Yeah. Thank you. It's been great talking to you.

Dominic:

Thanks. Bye. Bye. Alright. That's it for this week.

Dominic:

I would really appreciate if you can talk or share about this podcast. It's it's always helpful. Also, another way to support this show is by purchasing my course. There is always a link in the show notes. So on that, see you next week.

Creators and Guests

Dominic St-Pierre
Host
Dominic St-Pierre
Go system builder - entrepreneur. I've been writing software systems since 2001. I love SaaS, building since 2008.
Markus Wustenberg
Guest
Markus Wustenberg
Go course creator @golangdk. Also nerd, musician, photographer, glitter enthusiast, and minimalist. Mastodon: https://t.co/V44ZTEaSpH
045: Gomponent with Markus Wustenberg
Broadcast by