← Ingestions

Ingestion f0af4dd8 extracted

Format
transcript
Kind
talk
External ID
7. Radoslav Stankov - Component Driven UI with ViewComponent - wroc_love.rb 2024.txt
Content hash
ff149632dc0c
Source at
2024-03-22 09:00
Manual extractions are temporarily disabled.

Extractions (2)

Status Model Tokens (in/out) Duration Cost Nodes/edges Read set (nodes/edges) Time
completed claude-opus-4-7
299,821 / 11,080
80,226 cached ยท 13,371 write
169.0s - 20 / 49 147 / 2 2026-04-17 23:20
failed claude-opus-4-7 RubyLLM::BadRequestError: You have reached your specified API usage limits. You will regain access on 2... 2026-04-17 16:18

Content

[Applause]


everybody is this on okay great so yeah


hello uh I'm radoslav stano for for


short R I come from


Bulgaria uh I have a newsletter called


tips at arank of.com where I roll


basically what everything uh all my


slides are uploaded in speaker de


already because I tend to have a lot of


cot in my slides and I noticed that I


present some fast and people try to take


pH to and I switch the slides so don't


worry about it all the slides are over


here so if you again don't need to rush


to make all the photos for the slides


they will be online uh so I used to be


the CTO of produ hun where we had this


architecture which actually I really


liked um I was really happy with this


architecture we had like a rails backend


we had a graph C layer uh which was


connecting Apollo next GS and it was


great it fit our needs quite well and


when I was at produ hun I started this


side project uh called angry building


and I was joking that the goal of the


company is to rename the building to


happy building because everybody who


uses it should be happy after that so


this is basically an RP system for


facility


management and it started as a side


project it's something I was doing in my


weekends in my spare time so when I was


starting the system I put a lot of


thought into architecturing it like what


are the pieces which I wanted to use so


obviously I want to use Ruby on Rails


because I'm really good with that uh I


like JavaScript but I didn't want to


write a lot of JavaScript because it's


harder to test I didn't try to write a


lot of CSS even though again I'm very


big I like CSS but I wanted to try


Tailwind I wanted to have extensive


endtoend tests with basically because


it's like a business software it's very


important to know work end to endend


that was also the reason why I removed


JavaScript from it and the big focus of


the call Project should be domain I


didn't need to think a lot around like


Reinventing the wheels and building


Technologies so I laugh rub


a life a love rails but there is always


one butt in the story so uh the first


thing is in the rails folder when we


open a standard rails project there is


two folders that always so there is this


folder called helpers which most of you


most probably are familiar with there is


this folder named views and when you


think about those folders this is the


thing which gets to my mind this is how


I feel about those it's like you start p


pulling a partial you go to a helper


from the helper another partial another


one another one and this is how it feels


and it gets messy very quickly and for


eight years ago before I was doing a lot


of react and I started thinking a lot in


terms of component when I built my uis


so I was fortunate that GitHub released


this gem Co view components which was a


system to build


components in the view layer very


smartly named it very obvious so this is


the website this is how the view


components work uh they are if you think


here is an example if you have let's say


this field set where you have to enter a


bank account if you think about it you


have a component which is called field


set the field set component have a title


and content and in your rubby code what


you do is you say oh I'm going to render


a new instance of my field set component


and it's going to have the form and the


form going to have the inputs so this is


how the view component is going to look


like you just inherit from view


component base it accepts a title you


add it as an instance variable and then


you have this really nice earb template


which is your field set where you can


basically make the field set


and where does this content come from


like the F set had two things it has


component uh it has a text and title and


this content is basically what's the


block passed to your view component so


in this way you have something simple uh


one and that's it that's the view


component because we are in the Ruby and


rail world we are really great with


having awesome tools and view component


have this thing called previews and


previews basically allows you to render


your component in a safe space where you


can see how it looks uh it's very


similar to how when you do mailers you


you create your mail template and you


can see how your mail looks like and if


you add a gem called lookbook This is


how you get for free basically you can


boast all your components with their


previews you can check them


and yeah and stuff works and you have


the achievement you basically are


experts in view components that's it my


job here is done and I have half an hour


more so I mean you're an expert but


let's go to the next level let's see


more because that's all to it like view


components that's the way you use it but


the thing about it is the devil is


always in the details and now you have


couple of questions


what goes to the helpers what goes to My


Views what go what's a partial what's a


view component and I have


this antipattern in a raos app like I


really hate when I open a view and I


notice this just a wall of partials


which as we learned in the previous


panel it's very slow and if somebody


sees that and say oh now we're going to


use view components I'm going to do


stuff like that it's the same yeah it's


a bit faster but still it's it doesn't


help us it doesn't help us so I have


this mental checklist of when I'm going


to use a view component and where I'm


not because every tool has its place and


we as Engineers need to know when to use


one


so the way I use view components is


first if I noticed group of code that's


used between two


controllers I create I move it into a


component if it's something


reusable if uh I'm having a view helper


that was generating


HTML more than like two three lines I'm


also moving it to a view component if I


have have complicated if else logic like


something really deep where the


conventional logic is extract a


presenter decorator or whatever I move


this to a view compos component because


the view components are a nice place for


you to put logic in that you can


actually


test also if I have to copy paste a lot


of code like I noticed I'm pasting this


pattern changing couple of lines here


I'm making my copy pasting


easier also I'm using view components if


I have JavaScript in the mix like as


well as as we live we have to do


JavaScript at some point so if I have a


component that's connecting to a


JavaScript usually it's something that's


reusable as well so I wrapped it in a


view component so I can for example


connected to a stimulus or I mean I


don't use jQuery but you can imagine


jQuery where I don't use view components


which I think it's important like the


first place is I still use


partials in one place and that's


underscore form like I can imagine you


all created this partial code SC form


and it's like okay there is this form


that's basically the same as ADD and


create it's fine like basically this is


the only partial I use it works it's not


like a performance bottleneck and it's


fine it's not like a cardinal or


anything where I use view helpers I


still have like I think 20 view helpers


and they're basically helpers like I


have a function called format money


which doesn't make sense to be a


component it's basically a function that


gets a big decimal and formats it into a


money also I don't extract view


components form messy HTML I'm fine of


having like a very messy HTML in one


page because it's in one page and if I


try to make it clean it's harder to fix


it later like I have this philosophy of


like if I have a messy code but it works


I just isolate it I keep the messiness


closed so the next time I see the


messiness and I have a better idea how


to do it I do it so it's isolated and


this is basically my checklist for view


components the way I think about them is


think about like that you have helpers


those helpers are used inside of the


view components and view components


make domain components like the UA


component and the domain component so


those this is another concept which I'm


stealing from my react World where you


think about like this I have a helper


called format money and format money


formats money I also might have a money


component where for example if it's


positive it's it's green if it's


negative it's red if it's zero it's blue


it might have some UI then I have a


product price component where I give it


it an instance of product and it says oh


this is the product price and also it


might have like a discount code or


something else but that's how you I


layer the component logic team


myself what's not here is the header


component because it's not reusable it's


for one


page and this is how I structure the


components but I promise you a lot of


code and again talk chip I can talk you


all that theories and theories are


really great it's very nice to talk


about them but let's see something real


and uh let's see how we can show you


some real code so the first thing is I


really don't like to do render fi set


component title it's very long so I


created this helper called component


where you just give it a symbol you pass


whatever it's basically doing this very


simple interpolation yeah it do


performance overhead it's not very slow


though but it works it haven't sold my


application and it's a nice and you


would see to my code I'm just going to


use this component helper just makes the


reading kit easier so this is a real


page for my application it's basically


half of my application look like that


because it's an Earp system so it's


basically rendering Excel with fancy


fonts so let's break this down so if you


think about it the app has couple of


components


here it has the navigation the page


header the filter form the stats and the


table areas and those things are


components navigation component page


header component filter form component


stats component and table component and


those are the reusable components so


this is how the page looks like if you


see it fits on one slide it's very


readable you totally see what I mean


so again it fits on one slide


technically and we on a technical


conference but yeah let's Zoom a bit


because uh let's focus on this part


first so this is one component which


basically presents some statistics about


the table I called it the stats


component I'm very good with literal


names so the stats component code this


is the code from the page looks like


that and let me Zoom a bit just because


to make it a bit more visible to you all


and let's focus on the page on the code


this is the start component the stats


component uh again it uses my component


helper here there is this renders here


it looks like a fancy DSL but there is


nothing fancy here it's very simple so


if


we think about uh our UI there is this


concept of slots like a lot of the more


reusable things like if you make a UI


component often they have those slots


like holes you can put stuff in and view


components have this concept of slots as


well so if you think about the stats


component it's not it's list of smaller


stats it shows you a list of stats and


every stat is its own status stats


number


and in the future I might have something


else I can St have stats string or


whatever so far I just have stats


numbers and this is the definition of


the stats component stats component just


have this render many numbers which is


stats number


component and that's the whole code of


the whole component this is the


production variant I haven't removed any


sensitive data from here it's like that


and


um one thing I do here I have this Alias


number with number


is view components have this thing where


you say render manyu and render manyu


would give you this method code with


number which would create a new instance


of this component so it makes this DSL


and I don't like with number it doesn't


sound good so I just as it to number so


I can say number arguments and this


would create the new instance also again


I have the application component because


I put some stuff there uh what we'll see


later


the earb file of this component is very


simple it renders uh DL so it's actually


even semantically right and it basically


Loops to the numbers and that's it


renders them and works the stats number


component are a bit more complex they


have


um so they have this attributes which is


the title the amount from color link


because you make them clickable and the


component itself just gets those data


and this is most of the components you


do are just like that just


initializers and uh oops wrong button so


this is one of the functions in my


account application component which is


one of the hacks I have is I have this


Fetch with fullback where I passed a


color and if the color doesn't exist in


the list in it's going to capture an


exception in my error reporting in


development and test this is blowing up


in production it's being clocked but it


renders default things to the user so I


use this hack in a lot of places in my


application where when I build the app


you as developer get all the crap from


the app but the users get the the hidden


behavior and you Tres the notification


so it's a nice strategy if sometimes you


need to throw an error to to be like a


presentative but you don't want the


users to know about that so this is the


component not nothing special another


component on top of that is this filter


form so also from the panel discussion


there was the question about the 20


filters I also have 20 filters even more


in some places so much that I needed to


build a custom UI for those and let's


see how these components look like so


let's scroll down and uh let's focus


here I'm doing something which I call


the Builder pattern and what the Builder


pattern does is I'm making this form


component it's yelling a form object


which is very similar to the form object


that we have and laugh and hate in the


same time with the form helpers in rails


where I have custom builder methods


where to present what I'm the filter


form for so what I have here is I search


by query I search I se I have a select I


have date range it's basically a simple


form and in my UI I just Define that and


how does this work so this component is


a bit more


complicated actually I have implemented


this component before I knew slots


existed in review components because who


reads docs noway so I implemented it


before slots and it works and it works


well and I'm I mean I'm not scared I'm


to touch it I'm lazy to touch it so the


way I implemented this is I have two


attributes exposed one is what's the


action which is like the


URL which by default is no that means


it's the same page and inputs which is


just an array


and I have this Mo hack before render


content uh so in view


components the moment you call content


like the block this uh let me come back


so this block here is only executed when


you request the content valuable uh if


you have slots they are always executed


so this is like one of my hacks to


basically render Uh custom builder


pattern if I had slots here I wouldn't


need that so let's go to all the methods


so my search is


basically my inputs is basically a two


dimensional array a label plus


uh something and something is something


being rendered as HTML here I'm


rendering uh another search input


components and I'm basically giving the


name plus params and y


y the select I'm B I'm just using the


normal HTML select from rails like the


select helper it's select tag collection


from select it has a class if I need the


class and I just entered it it's just a


normal select I don't need anything more


in the future when I'm less lazy or my


business requires me this select would


become some fancy JavaScript select or


something like that now this


works uh and yeah again why don't I


don't use slots because I'm I


implemented this before slots and I'm


too lazy to change that texts text again


just input text nothing special nothing


fancy it


works uh another trick I have because my


application is multilanguage so it's


basically have to work in many languages


uh I have I found this hack and I have a


this helper called T label and tlel what


it does is it check if the value is


blank it returns a blank string it has


cases where I need that if it's a string


it renders it if it's a symbol it


basically tries to find it in the


translation table and in this way I can


just say give me a text and a symbol


name and it's going to translate this


name into the valous languages so this


is like an interation


trick date


range I here actually use two inputs I'm


a bit cheating and if I want to have


more like a fancy calendar or something


I can replace that at some point right


now I don't so I just have this and the


way I render this component it's very


simple just look through the elements


show the label and show the input


nothing more nothing less and this is


how this component looks like and the


nice thing about this is I have like 10


other methods here rendering 10 other


inputs types and if I need to change


them if I need to change like the fancy


select the fancy calendar I have like a


very ugly looking um amount and


searching for money input if I want to


change that to my whole application make


it a bit more ux friendly I can do it in


one place I don't need to change


anything else in my system my system


just is changing in one place and this


is like the level of abstraction where


where I like to


be so let's go to another place um this


thing the header like I told you doesn't


make make sense to create like a header


partial in this case there is logic here


so it makes sense for me to make this a


component so how does this look like um


so I have a component called page


header I know there's gems for that and


I hate using them for breadcrumb so I


just got my own breadcrumbs which is


basically an array so I have this header


and the header had breadcrumbs


and the breadcrumbs accepts various


things like for example if it accepts


like a domain object which is my case


building it knows that it uses the name


of the building proper links and yada y


y yada I have Herer action and header


actions is those buttons over here so my


whole page header component has three


things in it it has the breadcrumb the


page title and it has these um


actions so uh how is this


implemented uh I have couple of slots


here so here I have the slots from


breadcrumbs they're called breadcrumb


items because I have a helper called


breadcrumbs uh I have action slot which


is an action slot uh if you notice here


I'm like aliasing with action slots


because it doesn't look very very well


to just


actions which reads better for


me uh here the title I'm using another


of my t- magic helpers it's called the


display this is like the heart of my


internalization system uh this is the


whole the the whole way this thing works


so it basically gets an object and tries


to interrogate it into how can I


actually display actually with switch


this can actually be changed switch now


when I look about it with the new


pattern matching stuff but again too


lazy to change that uh and it's bad


thing to think about it on the stage but


yeah so the the thing this thing gets an


object and it tries to interrogate it if


you are a symbol you will be translated


if you are string you're going to be


displayed then if you have this I call


it display name this is how the world


sees you how you are going to be


displayed and the other one is when I


didn't have the display name inter I Ed


name or title uh and again they have


different semantic meanings so if you


have a name I show you the name if you


have a title I show you the title


otherwise I convert you to


string uh maybe I should lock an error


here but sometimes there is nulls so uh


yeah another cool trick here


is you can access rail helpers via every


view component so every view component


has rails helpers and rails helpers have


this content for which you can use to


set the page HTML title it's a nasty


hack not proud of that but it works


really well to sync your header title


with the page title you have it in


single


way here


oops here another thing I do here is


before


render I'm calling this function I call


it iner title because I started using


like oh I'll pass a title I'll p pass a


title here I'll pass title here I'll


pass title here and this get really


boring and I got very TI tired of that


and I had and I found a formula which is


basically the controllers have names and


resources have names and I have


internalization system so what I do is


if you don't give me an explicit title


for the page I'm going to infer it and


I'm going to check if you are an index


you have the name of your index in the


translation table and it's always Pages


underscore title whatever whatever


otherwise I'm getting the the


name the nor the


modularized and because this is already


being translated in some for some other


reason I get translated that so I don't


need to deal much with the


translations and this is how the page


HTML looks like and this is very clean


HTML it's nothing more logic and the


whole component removes a lot of area of


for my app and all my pages are very


consistent I have everything I want and


how much time more we have oh great so


we get to the big boy uh the table


component so uh the table component is a


component where it has a weird


history uh I before few components like


10 years ago I needed to make an admin


panels and I needed tables and I created


a helper we generated tables and I


basically copy pasted this thing for


years and just wrap it around like a


view component and right now it's a view


component but it started like basically


a view helper so this is how the table


component looks like you just say


component table you give it a


collection and you can say and you need


to use the builda pattern


for showing like what column it is like


what are the columns


and a column can be a


record which can be a name and it uses


the property itself of the record Being


displayed the record can be an apartment


that means this is like the apartment of


this building


object I can get like a block where I


buil like a custom logic in this case


I'm showing some


documents um I can have dates I have


money I mean my application have money


I'm not sure how much money I have but


the application has money so I have the


money component here uh and yeah this is


a very nice way to define table so far


and over the time I have added various


columns so let's see how this is


implemented also one thing to notice


here is I'm using components inside of


components so for example I have a


component named a batch component and


this is a component that R like a batch


which is basically half a circle with


like different colors and I have this


component with a very unique name called


uh let me read it because it's very it's


transaction kind batch component which


you know it's very Gable if you need to


replace it which gets a transaction and


knows what kind of batch it can render


to this transaction imagine in other


application that transaction can be


pending transaction can be failed


positive negative you can add a lot


business logic and hide that business


logic to how to display in single


place uh one thing where I used helpers


is I like nice nice the code to look


nice so I for buttons I have my button


component and I actually extracted this


very recently before for buttons I just


had like a button act button helpers but


I just have those helper methods because


it


it was kind of un natural to write


component button whatever whatever and


to do like


component compared to like just say Okay


butt an action also one advice to


everybody if you're making a new system


don't and it's very tempting when you


make a UI system to start to extract


components from component name button


leave the button component last like


button components are one of the most


used components in your apps a lot of


opinions about the buttons and there is


a lot of variance of the buttons so


don't overe extract button components


like the worst component you can start


your design system from is a button


because there are too many of them and


there will be too many of them


so most of the time you need to extract


a button not Implement a button and then


use it just friendly advice you'll thank


me later


uh so uh the table


component table component just have two


Fields records and


columns and here I have two things one


is for formatting money and formatting


dates uh and the initializer just


receives a list of records and it


creates an empty columns array I have my


for render


hack um and this is how the columns look


like so every column is just a plain


Ruby object called table column it's


that accepts name classes format which


is something that that can you can call


call on so basically a


function uh helpers which are the rails


helpers for rendering whatever and if


it's a block I'm just bypassing the


block so this is every column so with


this method you can Implement everything


in this table so all my helpers are just


using this thing I can say column name


number class number why do I need class


for number because you want all the


numbers to be on the on one side and be


always sorted uh why I want it for time


because there was something for time and


for I want to say okay I format the time


record is a bit more


complicated uh with record what I do is


I'm getting the record and I'm saying


okay um this attribute name the second


argument here is the attribute name and


I'm getting one of the properties of the


record and I'm trying to find the link


for it I'm using my friend T display


here I have this helper called routes uh


record path which basically for every in


my domain system can render a route and


here is where the itself hack works so


in Ruby every object has a property


called itself which returns itself so I


don't know if it's meant for uses like


mine to to be able to say oh my


attribute is itself so it renders the


class but it works so yeah the record is


a bit more complicated and the table


column it's actually quite short and


that's the whole code I haven't I think


I removed two comments here because I


forgot what they were uh for what the


code was so again I'm just getting a lot


of properties and I have two methods


render header which renders me the


header of the table and I have a render


cell which is the whole logic where you


basically render all the cells so render


sales does some voodoo magic to get the


block content it uses the display to do


a lot of stuff but again it's something


that you do once and the table itself


it's a lot simpler you just Loop through


the columns and for each column you use


the column thingy to


render either the header either the cell


and if it has pagination you show the


pagination if it doesn't have pagination


you don't do it so notice this works


with active record associations it works


with paginated things it works with


arrays


so it's like a very simple grid table


nothing fancy and over the time again I


changed its


implementation so yeah that's uh the


whole uh system and how it works I


wanted to show you some real Cult of


view components because they're very


simple like when you you become expert


for like five minutes and this could


have been the whole presentation but I


think there is value of like showing


stuff in real life like the the dirty


stuff like yeah so yeah thank


you yeah the slides are here thank you R


do we have any


questions thanks uh do you have


experience with react and what is your


attitude to it oh yeah I mean I have


plenty of experience with to react uh I


used to organiz can you compare this


solution with direct and your feelings


about uh so they're very different like


they have different uh value


propositions in my opinion like uh I


have for this company I have a mobile


app which is react native which is a


very like the same way view components


was a great solution for the back end


react native was a great solution for


the mobile experience so they are in my


opinion you need to think about what


interactiv ability your application


needs and what is the tradeoffs like for


example if when I was the in prod hunt


we use next GS with react if I use view


components with the rails way there I


would hate myself if I use SGS


with uh react for my for angry buildings


back end I would have hate myself like


there is this balance of is your


application needing this Technologies


can your applications take the


constraints and the disadvantages of


these Technologies because every


Everything is a trade-off and you have


to think about each technology comes


with its benefits hopefully it has


benefits and it has its drawbacks and


you need to kind of balance that in my


in in in these cases like my previous


company and this company they were


totally different products the


interaction ability model were very


different and and the teams the


constraints were very different and


again I can talk for hours why one is


better but talk come to me afterwards I


give


more okay any other


okay so one of the um advantages often


presented for view components is


testability I'm interested in your


experience um do you tend to heavily


unit test view components not um and


what your thoughts are yeah so uh it's


Advantage for testing what I I don't do


unit tests I do smoke tests so uh let me


show you this


uh so uh as I mentioned view components


have this awesome featured called


previews which oh my God this was too


long guys how did you so lookbook uh


like you you make those previews so for


most of my components I have those those


previews that work like M's previews


lookbook uh like view components renders


those in a page so what I do is capara


test that goes to each of those pages


opens it and makees sure it doesn't blow


up and this is well enough for me


because uh I have end to end test for


all the business logic and all the


business functionality so I know stuff


function it works I have most of the


logic in my components if it's something


more complex it's moved to like a


business service object or whatever and


I make sure I have smoke test for those


things don't blow up usually what's more


useful is having this lookbook where I


can check oh how does this look with


this variant of UI with this variant of


UI with this variant if I was making


like a real Library I would have this


would be a nice way to do like visual


tests where I render make a screenshot


and apply but I don't need


that okay any other


questions all right let's take a break


but first let's uh give a appla to R


thank you very much thank you great


presentation