My first event-sourced aggregate in Ruby…

Having read the last three posts, you could have an impression that we’re never going to start developing. Brace yourself because today we’re gonna do it! Today, we will take our keyboards and move the models we’ve proposed to the code. I like to define models we’ve created during DLES as “propositions”. That’s because whenever we sit down and start the implementation, things can change. That’s normal, and we call this process a modeling whirlpool. We will keep on asking experts about some details. Knowledge crunching is an ongoing process, and our models will evolve and adjust to new business requirements. Ok, so without further ado, today we will implement our first test for our first aggregate, and we will set up the whole stack with CQRS, Event Sourcing, and… Rails. Yup, you’ve heard that right, me, a Java fanboy, said that πŸ™‚

Note: all the code for this and future posts is available here.

Ruby? You’re kidding me, aren’t you?

After consideration, I came up with the conclusion that it will be the best for everyone. First of all, I will tell you what I get out of it. So, for a long time, Ruby has been on my TO-DO list, and now it is a perfect moment to learn it. We, developers, improve our skills when we try other languages because it shows us different perspectives. I used to work primarily with strongly typed languages, so jumping into weakly typed ones can be a pretty exciting experience.

Ok, that’s about me, now let’s switch to “objective” arguments  – or rationalization, you name it πŸ˜‰

The initial idea was to implement the whole infrastructure for the event-driven architecture (when you get back to the first post, you can see that was the plan). By “infrastructure,” I mean, for example, command and event busses themselves and their integrations. Also, we would need to have a post where we analyze different solutions and the reasons for choosing the specific ones. Moreover, we would need to do it somewhere between Design Level Event Storming and the first implementation of the aggregate. From a technical point of view, it would be a fantastic task. I’m pretty sure we would have a lot of fun with it, but at the same time, it would keep us away from the most crucial thing – moving the model to the code. So we would have a long interlude, and we could lose our zeal for work. Nevertheless, all is not lost. Now I will focus on the model implementation. Sometimes, if I’m tempted to show you how things work in Java, I might write a post about it πŸ˜‰

Regarding Event Sourcing, we would probably skip this fascinating concept and use a standard persistence mechanism. I also want to mention that currently there is no “native” Java solution that is an obvious choice for an event store. That’s why we would need to do some research and consider, for example, Event Store with its Java SDK (gRPC). Or maybe, we could drift toward Akka and the actor model. We could spend hours thinking about all those exciting tools, but I think this is not the right time.

Fortunately, while talking with Andrzej Krzywda about their (Arkency) Rails Event Store (RES), he asked if I would like to use it in this project. Of course, my first thought was: “no way – Java for life!” but then I realized that it actually makes sense. The outcome of Adrzej’s indoctrination was that the next day, I texted him about using RES in my project πŸ™‚

Below, a couple of arguments for going with RES in this case:

  • Arkency has used DDD in projects for years. They share knowledge by publishing posts, doing presentations, courses, and workshops, and they’ve also written an excellent book about DDD: β€œDomain Driven Rails”. Don’t let the title fool you – whether you are a Ruby developer or not, you should read it.
  • They develop a tech stack (RES is a piece of it) and techniques that have worked best for prod environments during all those years. In other words, their approach is mature and battle-hardened. It’s also consistent with how I see DDD.
  • RES provides us with the whole infrastructure for commands, events, and event sourcing. We get it out of the box, then we can focus 100% on  the most important thing – the model. That was the main reason why I decided to use it.
  • Last but not least: Andrzej promised that whenever I get stuck somewhere (remember – I’m still a Ruby noob), I can get some support or review from them πŸ˜‰

Now I’m pretty sure you are as excited as I am!

Let’s do it the “all-in” way!

By all-in I mean the approach where DDD, CQRS, and Event Sourcing are combined together. However, I’m aware that this may not be an option for most already running projects without revolutionizing the codebase. Therefore, if I want to show you a more evolutionary way (applicable to most projects), I would probably skip Event Sourcing in the early phase and go with some standard persistence mechanism. The distinction between write and read models isn’t so obvious too. I would probably start with something like “snapshots” from aggregates during the read operation. But the idea for this series of posts is different – I would like us to learn and practice concepts that usually are presented only in theory. When combined, those concepts can be a massive game-changer for every project.

One last thing before we get to the keyboard: I need to explain how I understand those three concepts, so we all are on the same page.

Even in the previous post, you could’ve seen the “aggregate” word in use. I assumed it’s pretty common in IT, so I skipped the explanation, but I would like to write a few sentences now.

Well, in aggregate, we… aggregate. So we collect data/objects that are grouped together as a logical unit. We protect its consistency. In practice, it means that the aggregate is the only place where this data can change. So we want to avoid situations where different pieces of code change them. That’s why an aggregate is also a place where we keep all invariants that help us keep everything consistent. Doesn’t it ring a bell? Consistency, data, and behaviors together. What was that? Encapsulation? OOP? πŸ˜‰

I also mentioned CQRS and Event Sourcing so let’s explain those two quickly.

CQRS (Command Query Responsibility Segregation) has its roots in Command Query Separation (CQS) proposed by Bertrand Meyer. It was even considered CQS at a higher level for some time. CQS itself says that a method of an object can do one of the two things: perform an action (change the object’s state) or return data to the caller, and never both of them. However, Greg Young took this principle a stage further and proposed to use it at a higher level. As a result, we have two separate models: the write and the read models. From the architectural point of view, it results in exciting consequences. On the one hand, we have pretty heavy write operations, where we keep complex business rules and protect data consistency. On the other hand, we keep lightweight read models – for example, DTOs created directly from specialized SQL queries results. 

We have 90% of reading operations in most IT systems, and only 10% write operations. So it means that if we have a dedicated read model, the whole system will be more performant than the same system, but with a single mixed model used for both: writes and reads. At the end of this post, you will see an example of the write and read model segregation in action. Stay tuned!

If you want to know about CQRS itself, I encourage you to read this document by Greg Young – the source of CQRS.

Last but not least: Event Sourcing. It’s nothing else than one of the objects’ persistence techniques. We keep only the newest version of the object’s state in the standard approaches you probably know from most projects. Instead, in Event Sourcing, we store all statechange events. Then, creating the object with its current state is done by “replaying” all those events. Thanks to that, we can also recreate any state from an object’s history. 

We store events in what’s called Event Store, and Arkency’s RES is an implementation of such a store.

I could write separate posts about those concepts, but what we have here should be fine now. It’s important to mention that those techniques can be used in the separation. You could even use CQRS in a project where you keep your business logic in services. Event Sourcing is just a persistence technique. None of them is required for the DDD approach. Nevertheless, all three combined together sum up to architecture (event-driven, with cohesive modules), typical for apps with a good design.

Ruby and the RES setup

Initially, I had a few issues with Ruby setup because I installed it as a root user on my Ubuntu. I did the same with Rails. It wasn’t a good idea. Especially now when I tried to install another version of Ruby using rbenv. Things started to collide. Finally, I uninstalled everything and started from scratch using this post. I assume that for other systems, it can be pretty similar:

  • install all required for Ruby dependencies (you may already have them)
  • install rbenv
  • install Ruby 2.7.6 using rbenv
  • install gems: bundler, rails

Now we can create a new RES project. The documentation and the tools that devs in Arkency have created can be helpful. All you need to do is run this command from a CLI:

rails new -m https://railseventstore.org/new YOUR-APP-NAME

It will bootstrap the RES project with all dependencies and default settings.

Then, if you run: 

rails s

and go to http://localhost:3000 in a browser, you should see a standard Rails page. Also, if you visit the http://localhost:3000/res URL, you should see the events’ browser.

It’s a good moment to confess to something… I do not like reading manuals – well, documentation is some kind of a manual ;). Of course, there is everything I should do on a RES page step by step. Why should I use it? That’s not for me. I’ve just managed to install a RubyMine, so I’m in the God Mode now – nothing can stop me.

Moreover, Arkency has created an Open Sourced example that I can spy on. I open it in a separate window on the second screen. I can see some aggregates, so I manually create them and the directory structure. I add something in one place, remove something else in the other – I’m pretty sure that eventually, it will work. Well, it did not. I took a few deep breaths and returned to the “What next?” section. We can see how the setup in the context of Rails looks or how we can change the events’ serialization approaches. But our next step now will be the initialization of a new Bounded Context, which can be done by a generator.

Let’s try it with the advertisements BC:

rails generate rails_event_store:bounded_context advertisements

After running this command from the CLI:

  • structure of directories for a new module was created:

advertisements
β”œβ”€β”€ lib
β”‚   β”œβ”€β”€ advertisements
β”‚   └── advertisement.rb
└── test
   β””── test_helper.rb

  • config for class loading was added to the application.rb file:

config.paths.add ‘advertisements/lib’, eager_load: true

Where to start? Test maybe?

It’s time to write our first test. Let it be the test for advertisements’ content change. Let’s start with finding this piece in our model from Design Level Event Storming:

We can move that straight into the code. First, we should throw the command that should trigger aggregate’s business method execution. Aggregate itself should protect consistency, and after execution, we expect a specific event:

The asser_events method is a helper method that I’ve stolen from Arkency’s sample app. It reads events from the event store and checks whether there are the same as the expected ones:

The test, of course, does not pass, so now we should focus on implementing all the missing things. We can see that we are missing two commands and one event for sure. The first command – PublishAdvertisement – is in the Arrange section because if we would like to change the advertisement’s content, it actually has to be published/created.

The project’s default configuration supports class loading from the advertisements/lib/advertisements directory. Nevertheless, I like to keep commands and events in separate dirs. That’s why I create those classes in such a structure:

advertisements
β”œβ”€β”€ lib
β”‚   β”œβ”€β”€ advertisements
β”‚   β”‚   β”œβ”€β”€ commands
β”‚   β”‚   β”‚   β”œβ”€β”€ change_content.rb
β”‚   β”‚   β”‚   β”œβ”€β”€ publish_advertisement.rb
β”‚   β”‚   └── events
β”‚   β”‚       └── content_has_changed.rb

We need to explicitly tell Rails where to find them in such a case. We can do it by adding a few lines to the config/initializers/zeitwerk.rb file:

Now we just have to implement all those classes:

  • PublishAdvertisement command:
  • ChangeContent command:
  • ContentHasChanged event:

We see that it’s still red when we run the test because we still miss commands handling and the aggregate that would throw the event. So let’s start with the handling of the commands. We will keep handlers in the advertisements/lib/advertisements.rb file:

Those examples show exactly how, in general, handlers should work. We should load an aggregate there, and then execute the business method.

Now we have to register our handlers on the command bus, and we can do it in the RES config file (config/initializers/rails_event_store.rb):

When we get back to the handlers themselves, we see the two last missing pieces: the aggregate and the repository.

Let’s implement the repository first (advertisements/lib/advertisements/advertisement_repository.rb):

You can notice here that RES via AggregateRoot class gives us an API for the repository. e can use that repository with the name of the events stream then. Theoretically, we could use this repository directly in handlers, but personally, I prefer having dedicated repositories per each aggregate. Mostly because I would like to have a coupling to the “framework” on the level of handlers. Thanks to this, we keep persistence details on the lower level.

By the way, you can also see here how the idea of event sourcing works. First, we pass a new object (Advertisement.new), the stream’s name, and a block/lambda. Then under the hood, events for the given aggregate’s ID are fetched and replayed on this newly created object. Finally, the given block is executed, which usually means the business method of the aggregate.

OK, so now we are almost there. The only missing part and the cherry on top is the aggregate’s implementation:

We have here business methods that protect consistency. Moreover, we throw events here.

What you see below business methods are event handlers in the aggregate context. According to RES’ convention, they start with on and then there is the event’s name. We’ve changed the aggregate’s state in those methods. We’ve done it this way because we want to separate responsibilities of running business rules and the state change. And that’s awesome!

Now let’s try to run the test one more time…

Hurray!!!

I would like to remind you the test and how it looks:

Actually, a single, specific line:

Please notice that we are expecting an event with the new content here. Now recall: do we keep this content in the aggregate itself? No. And that’s actually the most “mind-blowing” thing – we do not need advertisement’s content of the advertisement ;). The content is a view in our case. It’s needed only for reads. We do not have any business rules that require checking the content’s value. The only somehow connected rule is the one which says  that only the author can change the content, and we guard it. As I promised: we can sum this up as “CQRS in action”.

The one for the road

Can I ask you now for a bit of love <wink, wink>? Actually, a star will also work πŸ™‚ just take a look at the project’s code and hit a star if you like it:

https://github.com/stolarczykt/DevMountJob

If there’s one thing you can do today then please do yourself a favor and visit this repo and check how things are implemented with every new post. Just dive in there, clone it, run some tests, run the app. In other words: play with it and have a great time. See you next time!

Subscribe to the newsletter, so you will be the first to get to know about new posts!

* indicates required

The story of how to NOT start a project.

In the previous post, I described in great detail what we are going to do in the next few months. Today I would like to give you some insights into what was going on in my head when I was trying to launch that SaaS idea. This post is some kind of “behind the scenes” type of text. I’m going to show you how the idea was born, how I “validated” it, how much time and effort I invested in it, and finally how I failed. To sum it up, I will show you how to probably not start the project.

An idea was born

Like a lot of great ideas in this world, also this one had its dawn of time in… a drunk night. Well, I met my friend after a few months, and he said it would be cool to have a headhunter company. That company would verify developers and put them on their website in some kind of “auctions.” You may think of it as Amazon or eBay with developers ;). The idea popped up after I told him about the money I earned from recommending my friends for some job offers. As you can imagine, after a few shots, we were really optimistic about our great business model. We even talked about it a few times after that night. But an idea without execution is nothing, so suddenly it failed for its first time.

Later on, I was working on a project where such a reversed model of search used to work pretty well. That gave me extra energy to try one more time. I changed the idea quite drastically, as I wanted to remove everything, to skip the verification process and the need to run a headhunter company. The new idea was to just give developers the ability to add new advertisements – a simple CRUD application. On the other hand , there would be a search feature that recruiters would use. A few days of work and I could live my rich life ;).

At the same time, I read articles and listened to podcasts that were talking about problems in the hiring process. After “research,” I got to some conclusions that you can find in the previous post, so if you haven’t read it yet, catch up with it :). The idea was born at that stage, and my side project got the “DFS” codename, which stands for “Developers For Sale.” Yup, I know, sounds scary, but I can assure you – I was not objectifying developers ;). I had to think about a new name, and we will get to that soon. First, I would like to show you my business validation.

The idea’s “validation”

A real entrepreneur knows that before doing anything, the business idea should be validated. As an aspiring entrepreneur, I decided to create a pool. The problem was that I was pretty fixed on my vision of the final product, and I didn’t want to change it in any way. Instead of asking about pains in the hiring process, I asked users to anonymously leave their skills, desired location of work, and how much they would like to earn. Thanks to this, I was able to validate whether people are not afraid of sharing such a piece of information.

Ok, so at that point, I was set about what I was going to ask, but I had no idea where I could let people know about the pool. I had no audience at all. Asking people directly or on any Internet groups was a blocker for me. Luckily, a friend of mine is an IT blogger/vlogger, and he allowed me to put a short video on his vlog. That was actually an excellent idea, but at the same time, that’s the end of my entrepreneurial skills… Any business-oriented person would grab a smartphone to record a 2-min video, then would take some tool for creating surveys and create one in the next 5 mins. But no, I know better, I have to go “professional.” I need a name, a logo, designs. Moreover, a video had to be recorded by another friend of mine who does this daily. There had to be music in the background, my name popping-up, and a big logo, at the end of the video.

As a result, the survey itself ended up looking as follows:

After filling in the form and submitting it, a user was redirected to a “thank you” page. There were social media widgets to allow sharing, and a form to leave an email address. You may think now that something is not right here – I was talking about anonymity, and now I ask people to leave their email. Believe me or not, but I was really serious about the anonymity of users in that product. That said, I can assure you, that email form on the thank you page was not connected in any way to the survey. The only purpose was to build a mailing list of people interested in what was going on.

When all that was ready, my video was added to the vlog’s episode. There were no details about the product itself, just asking people to take part in the survey. I don’t recall exactly, but the numbers were around: 300 took part in the survey, and 100 subscribed to the mailing list. That was a great success for me.

First things first

Now let’s focus on “the most important” things in running your own business: the name and the logo. How are people going to fill in the form if there is no logo and name? Yup… That was me thinking about business back then ;). Nevertheless, the story is quite interesting, so I will describe it here.

Some time ago, I was working on a small side project with a guy who got his Ph.D. in History of Art. He came up with the name and designs for that project. I really liked them and the whole idea behind them. That’s why I asked him for help, as “Developers For Sale” doesn’t sound good ;). As he is also a Linux user, after a few days, he got back to me with the idea of “mounting a new job by developer” from a command line. Like you would mount a resource in Linux. It would look like this in CLI:

I was delighted. This was not only because of a reference to a command line but also as there was a “$” sign. Moreover, “mount” can bring to mind mountains (Mount Everest), which may be a reference to the career path. Mind blown, isn’t it?

Then I described the whole idea to the designer, and after a few days, I got such visualizations:

The first one got my attention, but now when I look at them, maybe I would choose the second one, as it’s a bit retro. Which one do you like better?

Both of them refer to a command line, and both have a “$” sign. Maybe its meaning is not so obvious when you take a look at it for the first time, but I was really proud of it. In case of earning millions of dollars on my new SaaS, I was prepared to explain this deep meaning in interviews ;).

Designs

I knew what kind of views/pages I wanted to have, so I prepared quite detailed mockups. I sent them and a project description to the designer, and,  after a few days, I had the first version that I accepted. You can see them below:

We are almost there…

Now the fun begins. Long story short, while working on designs, I asked the designer to also prepare designs for the survey form. Everyone knows it has to be custom, with a logo, etc. Instead of taking some out of the box survey tool, I decided to develop it from scratch and host on Elastic Beanstalk, as I really like AWS services. So I did…

A few days later, the survey was deployed and was ready for traffic. Results I showed you a few chapters earlier.

The β€œpost-survey” era

After initial success, I was thinking about how to get my great product even more traffic. I thought that content marketing would do the job there. My thinking was as follows: 

  1. write an article (mentioned in the previous post, link here),
  2. submit it to Hacker News,
  3. watch the mailing list grow to thousands of emails.

Well, as you can expect – it didn’t happen.

Writing an article took me quite a lot of time. I had some doubts that people reading it would hear my Central European accent, so I sent it to review to a friend of mine who is a great philologist. Fortunately, it was quite good, and only a few more natural collocations were added. Moreover, I thought that instead of stock photos, I would like to have some eye-catching sketches, so I asked a drafter to do them. Then everything was ready, I could submit my article about changing the world to HN and… nothing happened. I saw in Medium’s statistics that people were reading it, but only a few subscribed to the mailing list. Then I was sending back the link to the article in reply messages to job offers that I was getting at that time. It turned out that recruiters were quite interested in the idea. I was noting their contact details to let them know when I was ready with my product as I was supposed “to start soon.” As an idea without execution is nothing, I’ve never got back to them.

We got to the stage when I got really tired of all that “entrepreneurial life.” I was thinking of delegating the implementation of the prototype to another friend of mine. He wanted to play a bit with AWS, so we cut a deal pretty quickly as it was a win-win situation. A month later, I had a clickable prototype that I didn’t show to anybody. I think that besides personal reasons for not launching it, I also lost faith in its success. Some kind of excuses appeared, that probably would be better identified here by some coaching gurus, so let’s leave it here for them πŸ˜‰

What went wrong?

You probably already know what went wrong, but let me say that loudly. I focused on totally not important things, instead of focusing on my potential clients, getting to know their pains, observing them, analyzing their behavior, supporting them, and building a community. I did research supposedly, but that’s like with any other research – you can come up with such results that will support any thesis. Worst of all, I was defending the idea only because I wanted to do it.

With the benefit of hindsight and after seeing some success stories, I can admit that those totally unnecessary activities were: logo, designs, video, drawings, article, overthinking… All that consumed too much of my time, energy, and money. As a result, nothing was left for delivering real value and solving other people’s problems. That’s why I’d advise against taking such an approach in launching your side projects. Nevertheless, every cloud has a silver lining – at least we have a lot of resources and an exciting business domain to model.

If you have any questions about any of the fragments of this post, feel free to ask in the comments section, and I will reply. I also encourage you to share your experiences as I know that I’m not alone in such an approach to side projects πŸ˜‰

Last but not least, there is some really great stuff coming in the next posts about Event Stormings and Domain-Driven Design, so don’t miss it and subscribe to the newsletter below.

* indicates required

See how I failed at my SaaS idea and what you will gain from it.

Today I have a story for you. A story that would never appear in any of popular business or marketing books, because it’s a story of my failure. In other words – I didn’t do it. My idea for the great SaaS product has never come through. Nevertheless it recovers in my head from time to time. Likewise this time, but now it’s different. Instead of creating the SaaS in my basement without showing it to anyone until it’s done, I will share with you the whole process with all technical and business details. But that’s not all – hold your breath – it will be an Open Source project! That’s because I want to share with you a lot of practical knowledge about software design, software architectures, Domain-Driven Design in general, and its building blocks. Moreover, I’m going to show you how to efficiently gather business knowledge and requirements by running Event Storming sessions.
As a side effect, you will also get to know about how I wanted to make my living by selling the SaaS product to you and HR departments. You will see my motivations and how I was thinking about monetization and people’s behavior.
In the end, as this is going to be an Open Source project, I will encourage you to contribute to it by fixing bugs or forking it and implementing your own approaches. What’s more, you will be able to use it for your own purposes. If you have always wanted to be a marketing expert or an entrepreneur, feel free to take, deploy and run it as your own business. I don’t mind.

You may ask now why I want to show you everything and what I will gain from it. There are a couple of reasons for that.
First of all, it will help me to close that chapter in my life, and I will do it by creating my own Open Source project! Thanks to that, I will bump up some of my stats ;). Teaching others is the best way to learn, and more exercises equal more experience. After the whole project is done, I will gain +5 to wisdom on my character’s card ;).
I really like the business domain and the whole idea behind the project itself. Moreover, I also like the technical approach that I’m going to use here.

Second of all, I want you to learn new things from the areas of software design, architecture, and DDD. Those are usually techniques that can totally change your way of thinking about software design and business modeling, and I would like to share this knowledge with everyone.

Thirdly, it may be that the business model/idea itself is attractive only in my opinion. Some product validation would be required here, and if it failed, there would be no point in implementing it. But implementation itself is the most exciting part for me, so – no validation at all ;).

Last but not least, I actually had a prototype of the product, but I’ve never launched it. At that point in time quite a big change in my priorities happened, so building the audience and marketing of the product fell all way down on my list :). Launching and maintaining such a project is a huge responsibility, and I couldn’t afford that. One can say those are excuses, but I don’t really care. I told you at the beginning of our adventure – you would not read this story in any coaching/marketing book. You are here to learn a load of new technical and modeling stuff, so let’s go.

Our schedule

I will show you now what is going to be included in the whole post series. A small disclaimer that the order of the topics can change as well as the area of expertise will probably stretch as with me thinking about it every day, new ideas pop up :). For now, it looks as follows:

  1. Domain description. This is the post you are reading right now. The idea of it is to explain to you the whole business model. Also, my motivation to create such a project back then as well as now. I highly recommend you should read this post as it is the starting point of our journey – you need to know the domain of the problem to have a good understanding of what’s going on later on.
  2. Genesis. In the second post of the series, I will be brutally honest with you. I will show you how to probably not start such a project. You will see how much energy I put in places where I could simply do nothing. To sum it up, I will show you how the logo and designs were created, how I “validated” the idea, and my ineffective attempts at content marketing.
  3. Big Picture Event Storming. I will show you there my first event storming on that project, and you will see how cool it is to do it with a person that has a lot more business experience than you.
  4. Design Level Event Storming, where we will split the business model into Bounded Contexts and Subdomains.
  5. Architecture or even architectures’ style pick πŸ˜‰
  6. Documentation – general one and for architecture decisions.
  7. Project’s setup, which in this case means package structure, VCS, and CI.
  8. Aggregates, strategies, repositories, services, etc. This one will be split into a few separate posts as there is a lot to say about each of those DDD building blocks.
  9. Commands and their infrastructure.
  10. Events and their infrastructure.
  11. Deployment.

Domain description

The domain we are going to work on is an initial phase of devs’ hiring process. To be precise, turning it upside down, so developers, instead of browsing job offers would create their own, anonymous, time-limited advertisements. They would put their expectations there and wait for recruiters with offers. To sum it up: “I’m a strong and agile/waterfall (dad joke alert) developer for sale.” I know – may sound like I was objectifying and treating developers as regular resources. Well, please forgive me – I was young and needed money ;). But if you think about it, it was actually the opposite as it was going to give everyone the same start – more on that later.

The detailed genesis of that idea will be presented in the next post, but for now, I will just say that the final form of it developed based on research I did in this area. There were, and actually still are, a lot of new articles/podcasts/videos every few weeks that point out what is wrong with the hiring process. Moreover, I was directly asking devs and people from HR departments about their experiences. It turned out that recruitment-related problems are not solely bound to the interview but start ahead of it. The issues were reported on both sides β€” both the developers’ and the recruiters’.

Developers’ side:

  • If not looking for a job, they would not like to keep being informed about new possibilities of employment.
  • Job adverts are unstructured – form reigns supreme over content, terms, and conditions of employment are not presented clearly enough.
  • Talking about the salary is the stressful part of every job interview. Candidates fear their demands might scare a potential employer away. On the other hand, they are also concerned they may not be sufficiently appreciated and end up underpaid.
  • There are concerns that should they come across as underqualified, they may be tempted to lower their expectations with regard to the pay during the actual interview, compared to their pre-interview estimates. Let’s connect it with the imposter syndrome here ;).
  • Another concern is that by presenting your thorough profile, you may end up being discriminated against or being offered relatively poor terms of employment due to certain characteristics (such as your gender or background).
  • Lack of information about the salary bracket in numerous ads, which makes even ballpark estimates as regards a company’s financial capabilities impossible.

Recruiters’ side:

  • A lack of a selected target group β€” knowing who is available would make it possible for them to come up with much more personalized offers.
  • Annoyance with no response whatsoever to either social media- or e-mail- based job offers. In other words, recruiters often end up addressing people who may not be interested in changing jobs at that given moment.
  • Having a set budget for salaries at certain positions while not being allowed to openly present it in job adverts.
  • Candidates’ demands as presented during the interview, which does not tie in with what the company can offer.

Possibly some of them have already been addressed, thanks to new job boards that present job offers in a structured way and exposing, for example, salary information. I’m not up to date with it. Nevertheless, I still find the business domain/model exciting as it is still some kind of reverse flow, so it’s a perfect candidate to model and implement it together with you. The domain is complex enough not to be another example of a pet store project.

I’ve already mentioned that my idea to solve the above problems would be reverting the initial phase of the hiring process by handing it over to developers. This could improve the process in a few areas:

  • Isolating the target group, or the developers searching for work, from the total number of developers on the market. Thanks to this, recruiters will only direct their offers to those actually interested in them.
  • Developer advertisements would be standardized and stripped down to basics, such as financial expectations or the location of your employment. It is also crucial that the candidate’s technical profile be presented in a lucid way.
  • Clarity with regard to conditions from the word go – even before the interview. Thanks to the suggested approach, both sides are on the same page right from the start. This also improves communication between them further on into the process. Additionally, it eliminates cases of developers being tempted to undersell their talent following an interview that did not go according to plan.
  • Developer anonymity. Apart from the obvious reason which is wanting to keep your current employer in the dark about being on the lookout for some new prospects, there are countless others. An example of these would be equalizing the ground rules for all involved β€” you present your skill set and requirements, thus creating the basis for a preliminary assessment. It ensures that those offering a job are not taking into consideration things they shouldn’t be. Thanks to this, the interview is solely based on your merits.
  • No needless networking. A notice with your offer is only displayed for a set period of time. There is no room for standardized profiles or networking here. You choose to use this tool only when you really need to.
  • Speeding up the recruitment process. Through a clear set of candidate’s demands, recruiters can see right from the start whether or not these can be met. Then all they need to decide is whether to accept the conditions and make an offer or to keep on searching for the right person.

Now we come to the point when I would like to present my business requirements regarding the new flow of the hiring process: 

1. A developer creates an advertisement:

  • The advertisement is time-limited just so as not to hang there forever.
  • A few adverts can be active for the same developer at the same time. There can be a few reasons for that. For example, a developer is a Ruby developer and looks for a job in Ruby. Still, he/she would also like to check whether with that experience they can get any offer as an Elixir developer. Then a second advertisement could be created.
  • Each of the advertisements can be temporarily unpublished at any time. For example, when we get a lot of job offers and don’t want to get more of them. On the other hand, permanent removal should also be possible. That’s in case we reach the limit of free advertisements but want to create a new one. And now we move to monetization $$$.
  • The initial idea was to charge for each advertisement. The assumption is, that if you are looking for a job, you will be willing to pay $5 for that. Nevertheless, there is one problem with such an approach – you will not pay if you totally don’t know the product and its potential. That leads me to two solutions:
    • Limit for free advertisements, and each one above this limit is chargeable.
    • Tiered pricing, where the first tier is β€œfree” with 2-3 advertisements. Higher tiers allow you to add more of them and give you extra features. Regarding those features themselves, they are not defined at all. But I’m thinking about some advertisement’s highlighting and showing statistics. You know – a developer seeing charts equals a happy developer ;).

Because I still consider the first approach some kind of edge case, I decided to go with the second option. The other advantage of it is that tiers usually should increase your revenue, and if people have 3 options, some of them will take the lowest tier (free in this case), some the middle one, and there is also a part that goes for the most expensive one.

As the tiered approach requires some features defined and I have no idea what they could be, it would be great to make this piece of process flexible enough to support both options (or more). We will start with free advertisements and the limit for the number of them, just to postpone the decision of the final approach.

2. When an advertisement is published, it’s also available in the search component. That’s the most interesting part for headhunters and HR departments. When a developer decides to unpublish or delete an advertisement, it should also disappear from search results.

3. A recruiter can make an offer to an advertisement. A few interesting requirements kick in here:

  • A concrete recruiter can make only a single offer to the specific advertisement. That’s because we want to prevent spam – sending the same offer multiple times to the same advertisement.
  • If a recruiter wants to make an offer, he/she needs to accept all of the developer’s expectations, which are marked by the developer as required ones.
  • While making an offer, it’s required to fill in contact and company data.

4. Developers can see all offers in their admin panel. Each offer can be deleted. In this case, the developer will not get the same offer again, as recruiters can make an offer only once to the specific advertisement (requirement from point 3). On the other hand, if a developer finds any offer interesting, they can use contact details and take the rest of the communication process outside of our SaaS app. That’s actually the intended operation as we want to be as anonymous as we can, so we don’t want to have any communication or storing any sensitive data (CVs) within our app.

That’s it when it comes to the domain description and requirements. You should know now what kind of problems I have spotted in the hiring process and what my brand new idea to solve them is. I described it some time ago in a different article that you can find here. Its purpose was to do some content marketing, so I submitted it to Hacker News, but as you can suspect – it didn’t go viral ;). I leave it here for you just as a fun fact, because the most important one for our upcoming adventure is still the one you are reading right now. We have here the domain description and business requirements in greater detail. That’s an excellent base for Event Stormings that I will describe in the next few posts.

I gave you my word that I was going to show you literally everything and to be brutally honest. Speaking of which, in the next still non-technical post, I will describe to you the whole genesis of the idea. I will show you how the logo and designs were created, how I was gathering information from developers and recruiters, and finally, how I failed. To sum it up: I will show you how NOT to start such a project. All this can give you an even better context of the situation and can help you in your side projects. That will be the last non-technical post, and later on, we’ll jump directly into domain modeling.

I would really like to spread the word with the idea of such an Open Source project, so if you, too, find this idea interesting, please help me and share it with your friends.

If you would like to see Domain-Driven Design and Event Stormings on a real-life example, don’t miss the next posts. Subscribe to the newsletter, so you will be the first to get to know about them.

* indicates required