00:00:00.840
Foreign.
00:00:06.500
Hello everyone! I want to start my presentation by introducing myself.
00:00:13.980
I hope everyone here knows what RBS is; I developed it.
00:00:21.359
I’m also one of the maintainers and I work for a company that was named Square last year.
00:00:28.320
I like the new name because some people were confusing the company I work for with Shopify or Stripe.
00:00:37.559
There are so many similar names in this area, such as Shopify, Stripe, Square, and Sega.
00:00:43.200
Anyway, this year we have five talks related to RBS and type checking, which is very exciting for me.
00:00:50.879
It was a great experience to watch the live streaming from my home while people were discussing RBS.
00:01:03.059
It was very impressive, but there is one thing that makes me unhappy.
00:01:10.320
Most of the talks, three of the five, focused on generating RBS. I know that's an important topic.
00:01:18.119
However, I want to discuss how we can use the type definitions.
00:01:25.020
It's great to hear presentations about using method types in RBS signatures.
00:01:30.200
Yet, I want to focus on using that type information to read or write code.
00:01:36.540
This leads us to type checking.
00:01:42.600
Before going into my talk, I want to quickly introduce the latest version of RBS.
00:01:48.180
The current version is 2.7.3, and it is in pre-release.
00:01:53.460
To install it, you need to use the --pre option.
00:02:01.920
A new feature of version 2.7 is the support for declaring the type of self in blocks.
00:02:08.880
Let's look at two method definitions.
00:02:17.099
In the first method, it receives a block, and we use square brackets to specify the type of self inside the block.
00:02:24.560
In the first method, 'self' is a String within the block.
00:02:27.420
This is especially useful for base classes.
00:02:33.000
In the context of RBS, self as a type is beneficial when we declare the type of the receiver.
00:02:40.620
RBS version 2.5 was released two months ago and includes a batch cross-talk feature.
00:02:46.500
If you specify the --out-dir option, it will scan all of the RBS files in your project and generate RBS files in the specified output directory.
00:02:52.340
Another feature I want to introduce is RDoc Praveen.
00:02:58.080
This is a project supported by Google Summer of Code.
00:03:04.379
I'm mentoring one student who implemented this feature.
00:03:11.159
This will generate RDoc documentation from RBS files instead of RB files.
00:03:16.440
It scans the RBS files and detects the class definitions, module definitions, and method definitions.
00:03:21.840
Then, it creates an RDoc output.
00:03:27.900
Now, I want to discuss the benefits of type checking.
00:03:33.960
When we have a Ruby codebase that's type-checked with RBS, it means we have RBS definitions for each class, method, and module.
00:03:39.060
This will help us understand the code better.
00:03:42.560
The RBS files work as API documentation.
00:03:47.759
When we add new features, it will assist you in writing the Ruby code.
00:03:53.160
Refactoring will also become somewhat easier.
00:03:59.700
I want to start with a demonstration of the Loopy project with type definitions.
00:04:06.600
I will demonstrate how the hover, go-to-definition, and completion features work.
00:04:11.400
This is older.rb, which represents a POS system.
00:04:17.100
We have the order RBS file that includes method definitions for each payment method.
00:04:24.180
When we hover over each payment method definition, it will display the method signatures.
00:04:30.060
If we point to the block, it will show the type of local variable within the block.
00:04:39.660
The completion feature also works with different payment methods.
00:04:45.180
This includes various Active Record methods.
00:04:50.280
We can use it with methods like 'where' or 'select' to define methods on that type.
00:04:57.660
Jumping to the definition is somewhat supported.
00:05:04.080
If we hover over a constant, it shows the class definition of that constant, allowing us to jump to its definition.
00:05:10.560
By clicking on the total method and selecting go to definition, it jumps to the method's definition.
00:05:17.880
If we have a string here, it will report an error.
00:05:25.500
This is because the gross type is an integer and there is no plus method between an integer and a string.
00:05:30.480
This demonstration illustrates how we can use the IDE effectively with RBS definitions.
00:05:39.840
The next demonstration will cover how to get started with Steep.
00:05:44.520
We will discuss setting up gems, generating RBS files, and running type checkers.
00:05:50.040
This is a demonstration of the demo application.
00:05:58.800
Assuming we have a point-of-sale feature, we have four modules.
00:06:05.640
The order module corresponds to the sheet.
00:06:11.400
The order item module represents the items you get from the shop.
00:06:19.200
The other two modules are cash payments and account payments.
00:06:26.160
These objects represent the payments you give to the shop.
00:06:30.960
Now, let's edit the gem file.
00:06:35.200
We will add some setups, including gems like Steep, RBS, and RBS Rails.
00:06:45.120
We need to ensure we use the previous version here.
00:06:50.880
After adding these, everything will now be installed.
00:06:55.800
Let's see if it works.
00:06:58.800
I want to have a Steep version 1.1.1, which is the latest previous version.
00:07:05.280
Next, we run the Steep command to execute this setup.
00:07:11.040
We need to run RBS correction to create the RBS type definitions.
00:07:18.840
We need to declare the dependencies for RBS libraries.
00:07:25.920
Some gems have RBS files of their classes, but we need that.
00:07:31.560
Here’s a list of required RBS files.
00:07:38.880
In this case, we don't need to include RBS files for gems like Steep itself.
00:07:42.600
We will add the ignore option.
00:07:51.600
Run the RBS correction installation, which will download the necessary RBS files from the gem correction repository.
00:08:00.000
Trigger me. It might take some time.
00:08:06.000
So let's skip this and move on.
00:08:10.680
We need to set up the local gem repository for using RBS corrections.
00:08:18.120
Please read the documentation for each repository.
00:08:24.600
Next, we can install the RBS value break tasks.
00:08:30.540
This will generate RBS files for the database modules.
00:08:35.880
We will have an asking directory here with RBS files for each module.
00:08:41.880
These modules are generated from the runtime information of Active Record.
00:08:49.680
Active Record modules have methods for each attribute.
00:08:56.160
The method definitions are generated accordingly.
00:09:01.680
Now, let's try running the Steep check.
00:09:07.560
Uh oh, I don’t have Steep installed.
00:09:13.560
Let's add it and check it again.
00:09:19.440
Oh, and we forgot to add the Steep configuration file.
00:09:26.160
This configuration file defines our type check targets.
00:09:35.400
Now, I will run the Steep check.
00:09:42.000
Let’s see what happens.
00:09:49.440
The RBS collection is installed. Why do we need that?
00:09:54.600
Okay, unfortunately, it's not working at all.
00:10:00.840
Oh no.
00:10:02.760
I need to skip the demonstration of this part.
00:10:14.760
I'm really sorry we have to skip part of the demo.
00:10:18.000
I had planned to show how we can start type checking existing Ruby code.
00:10:25.440
We generated some prototypes of RBS files and edited them.
00:10:31.560
We will find some problems and fix them.
00:10:38.040
Once we keep the demonstration and return to the presentation,
00:10:45.240
I want to emphasize that we should focus on the parts we work on.
00:10:52.200
There's no need to fix all type errors when starting type checking.
00:10:59.400
You will work on parts of the codebase to add new features or fix issues.
00:11:05.880
Then, you will write the RBS type definitions at that time.
00:11:12.240
This example demonstrates checking the Steep repository itself.
00:11:19.800
There are more than 1700 programs annotated in Steep.
00:11:26.280
In fact, we have more than 2000 entries in this repository.
00:11:36.660
But I find it more effective to write new code with the type checkers' assistance.
00:11:43.560
Another point is that to maintain new safety, you should test every time before using a value.
00:11:50.760
Optional types are useful here.
00:11:57.840
We might need to write some type interpretations to help the type checker understand your code.
00:12:04.920
We may also need inline annotations to support metaprogramming or casting.
00:12:11.880
However, keeping type checking as the last resort is essential.
00:12:18.600
Now, let's discuss how we can write new code using types.
00:12:25.560
I found that type checking against existing Ruby code is not very rewarding.
00:12:33.900
You know that there are no critical bugs because you have tested them.
00:12:39.840
Your team might review them or they are already in production.
00:12:46.440
Steep will only detect minor problems, which may not make much sense.
00:12:54.840
It may require too much workaround or inline annotations for minimal benefits.
00:13:02.400
Therefore, I think writing new code is more beneficial.
00:13:09.840
There are bound to be some unknown bugs in new code.
00:13:15.840
I want to add some features to the demo app.
00:13:21.120
I will show how to define APIs in RBS.
00:13:30.960
I also want to demonstrate that writing the implementation with a type checker will help.
00:13:37.920
Now, we'll allow audience interaction by allowing input of item names.
00:13:44.280
We also plan to add filtering options for updating or predicting payment methods.
00:13:53.880
I want to call this class the 'SearchService'.
00:14:02.760
This is a simple implementation, where the name of the item is passed to the initializer.
00:14:09.840
We construct some queries based on the orders and return the respective orders.
00:14:17.520
The implementation will replace the junction definition.
00:14:25.920
I want the implementation to look straightforward.
00:14:34.560
I will support some other types of queries.
00:14:39.000
Let's add a module called Query with classes representing different payment types.
00:14:48.720
These classes will represent paid by card and paid by cash.
00:14:56.280
I will define methods that translate the input into arrays of queries.
00:15:03.960
This way, we can classify items based on payment types.
00:15:11.160
Next, we will set up the RBS type definitions.
00:15:20.280
Now, let's implement the features.
00:15:28.560
The reader queries will call the respective methods.
00:15:35.880
Next, we will initialize the inject method.
00:15:41.160
We will use a case statement to handle different query types.
00:15:45.960
Queries could be based on name, payment method, or other types.
00:15:54.240
Now let's implement these methods accordingly.
00:16:01.440
The name query will have an attribute.
00:16:09.120
Be sure to account for payment types correctly.
00:16:16.080
At this point, you can do that with joins.
00:16:21.480
This is how to implement the search method.
00:16:29.520
This shows how I’m using type checkers.
00:16:38.640
You'll notice I used union types instead of inheritance.
00:16:46.560
I think it might be beneficial to add some base class.
00:16:54.840
However, with union types, we can do almost the same things.
00:17:02.760
We have the union type of credit name and can use case when for analysis.
00:17:10.320
There are two styles: one uses inheritance and method calls, while the other uses union types.
00:17:18.240
You can choose the style you prefer.
00:17:25.920
Some rules apply, especially when you know the set of types.
00:17:32.640
In this case, you can use union types and case statements.
00:17:38.760
If you don’t have a specific set, inheritance may be better.
00:17:44.280
This relates to the expression problem.
00:17:51.720
Union types generalize optional types.
00:17:58.560
Optional type is equivalent to union types.
00:18:05.280
The type checker will help to analyze all possible cases.
00:18:12.720
If you add new types, the type checker will notify you.
00:18:21.000
This is a small diagram representing how to work with types.
00:18:27.960
We have a concept application called test RBS and design document.
00:18:35.880
RBS type definitions lie between testing and design documents.
00:18:43.920
Writing type definitions is easier to change than implementing or testing.
00:18:50.760
Writing types and code is a back-and-forth process.
00:18:58.440
You write some types, then code, fix issues, and refine types.
00:19:05.520
This highlights the iterative nature of development.
00:19:12.480
Steve can be used, but there are alternatives like RubyMine.
00:19:19.440
RubyMine has its own type checkers yet can support RBS.
00:19:26.760
I had planned to demonstrate this, but it didn’t go well.
00:19:33.600
You will benefit from types when writing new code.
00:19:40.680
Type-checking existing code is less rewarding.
00:19:48.840
Writing types and implementing code should go hand in hand.
00:19:55.200
Using case when without type checking can establish best practices.
00:20:02.520
Having type checkers or writing types can redefine the best APIs.
00:20:11.880
This ultimately leads to better programming.
00:20:17.880
That’s everything I have for today. Thank you for listening!