Slide 1

Slide 1 text

@tagomoris (Satoshi Tagomori) 
 RubyKaigi 2024 @ May 15, 2024 Namespace, What and Why Introducing “Namespace on Read”

Slide 2

Slide 2 text

@tagomoris Satoshi Tagomori Maintainer/Founder: OSS: Fluentd, MessagePack, 
 Norikra, Woothee, …
 Event: ISUCON Service: Pathtraq

Slide 3

Slide 3 text

https://www. fl ickr.com/photos/takkanm/3978417669 Asakusa.rb

Slide 4

Slide 4 text

Namespace on read https://bugs.ruby-lang.org/issues/19744

Slide 5

Slide 5 text

Who does “Namespace on read” consist on? Special Thanks to Matz, and …

Slide 6

Slide 6 text

Special Thanks to Matz, and … Great advisors and motivators Chris Saltzberg
 @shioyama Yusuke Endoh
 @mametter Yuichiro Kaneko
 @spikeolaf Hiroshi SHIBATA
 @hsbt Koichi Sasada
 @ko1 Misaki Shioi
 @coe401_

Slide 7

Slide 7 text

What is Namespace?

Slide 8

Slide 8 text

What is Namespace? Separates apps/libs
 into isolated “spaces”
 (in this session)

Slide 9

Slide 9 text

Namespace Separating apps/libs into isolated spaces • Load apps/libs in a space • Hide changes from apps/libs in a namespace to other spaces • Run methods de fi ned in a space with de fi nitions in the space

Slide 10

Slide 10 text

Before Namespace: Global Only All classes/modules are shared in the entire Ruby process Ruby Process Application Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7)

Slide 11

Slide 11 text

Collision: 2 versions of 1 library cause errors Ruby Process Library Code DB::Client (v3) 😵 Application Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7) Before Namespace: Global Only

Slide 12

Slide 12 text

Ruby Process Namespace Load apps/libs in a space Namespace Application Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7)

Slide 13

Slide 13 text

Ruby Process Namespace Hide changes from apps/libs in a namespace to other spaces Namespace Application Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7) Library Code DB::Client (v3) 😀

Slide 14

Slide 14 text

DEMO

Slide 15

Slide 15 text

👏👏👏👏👏

Slide 16

Slide 16 text

Ruby Process Namespace Run methods de fi ned in a space with de fi nitions in the space Namespace Application Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7) Namespace Library Code DB::Client (v3) Namespace Application Code App::Func2 User Library Code ActiveSupport (v6) Application Code call call call

Slide 17

Slide 17 text

Namespace (revisit) Separating apps/libs into isolated spaces • Load apps/libs in a space • Hide changes from apps/libs in a namespace to other spaces • Run methods de fi ned in a space with de fi nitions in the space

Slide 18

Slide 18 text

Why do we need Namespace?

Slide 19

Slide 19 text

Why do we need Namespace? To avoid collisions of
 names, de fi nitions, and versions

Slide 20

Slide 20 text

Name Collisions No one can use a name in two ways • Structured names • Foo::Bar::Baz • Major scenario: • Top-level “User” or “Configuration” classes (gems, apps, etc) • Two apps in a process (in the context of “Modular monolith”)

Slide 21

Slide 21 text

Definition Collisions De fi nitions can be modi fi ed, globally, from anywhere • A single Module/Class instance • Example: Oj.default_options = {symbol_keys: true} • A single Module/Class definition • Process global open classes (monkey patches) • A single set of constants • A single set of global variables

Slide 22

Slide 22 text

Version Collisions Two di ff erent versions of a library can’t be loaded • Application libraries and library dependencies • App uses X, and Y ver 2 • X depends on Y ver 1 • “Dependency hell” • App uses A and B • A depends on C ver 1 • B depends on C ver 2 App C ver 1 C ver 2 A B App Y ver 1 X Y ver 2

Slide 23

Slide 23 text

Why is the Namespace “on read”?

Slide 24

Slide 24 text

Why is the Namespace “on read”? To keep using tons of
 fantastic rubygems as-is!

Slide 25

Slide 25 text

Namespace “on read” “on read”: apps/libs into spaces when loaded/required • “on write” approach • Libraries (gems) need to be written in the namespace manner (on write) • Update all gems in rubygems…? 😱 • “on read” approach • Libraries/Apps are loaded into spaces when loaded/require (on read) • We can use all gems as-is, with bene fi ts of namespaces

Slide 26

Slide 26 text

How can we implement Namespace?

Slide 27

Slide 27 text

How can we implement Namespace? De fi ning classes/modules under a namespace
 Loading extensions locally
 Having class/module de fi nitions per namespace

Slide 28

Slide 28 text

Defining Classes/Modules Under a Namespace (NS) • Namespace as subclass of Module • Use existing mechanism of load(file, module) • Load .rb fi les (A::B) under a module (M) → M::A::B • See also: “Multiverse Ruby” (RubyKaigi 2023, @shioyama) • Modify C API to de fi ne class/module: class_alloc (in class.c) • Create classes/modules (X) under a namespace (NS) → NS::X • To support extensions (.so/.dll/.bundle)

Slide 29

Slide 29 text

Loading Extensions Locally Extensions invisible globally, accessible explicitly • Extension fi les can be loaded 2 times or more • Loading extensions (.so/.dll/.bundle) in namespace • Copying the extension fi le to a tmp dir with PID & namespace pre fi x:
 my_ext.so → 515_160_my_ext.so • Using RTLD_LOCAL only when RUBY_NAMESPACE=1 • Hide exported (C) symbols to other extensions

Slide 30

Slide 30 text

Having Class/Module Definitions Per namespace • Open class in NS can modify built-in classes/modules • For monkey patches in namespace: class Object; def blank?; … • In other NSs: Object without #blank? • Class/Module de fi nition: classext (struct: rb_classext_t) • super, method table, constant table, instance variables, subclasses, … • Switching classext realizes a class with di ff erent de fi nitions! 🤪
 (Thanks to @_ko1 and @mametter)

Slide 31

Slide 31 text

Copy on Write of classext Having Class/Module Definitions Built-in Class/Module User’s Class/Module Class/Module Example Object String Kernel JSON ActiveSupport MyAppUser Root Namespace ✅ ✅ ✅ Main
 Namespace Namespace
 A Namespace
 B Before Running User Scripts ✅ classext readable/writable

Slide 32

Slide 32 text

Copy on Write of classext Having Class/Module Definitions Built-in Class/Module User’s Class/Module Class/Module Example Object String Kernel JSON ActiveSupport MyAppUser Root Namespace 🔒 🔒 🔒 Main
 Namespace ✅ ✅ ✅ ✅ Namespace
 A Namespace
 B Running User Scripts (without NS) ✅ classext readable/writable CoW 🔒 classext read only Read unchanged one

Slide 33

Slide 33 text

Copy on Write of classext Having Class/Module Definitions Running User Scripts with NSs ✅ classext readable/writable Built-in Class/Module User’s Class/Module Class/Module Example Object String Kernel JSON ActiveSupport MyAppUser Root Namespace 🔒 🔒 🔒 Main
 Namespace ✅ ✅ ✅ ✅ Namespace
 A ✅ ✅ ✅ Namespace
 B 🔒 classext read only CoW CoW Read

Slide 34

Slide 34 text

Copy on Write of classext Having Class/Module Definitions Running User Scripts with NSs ✅ classext readable/writable Built-in Class/Module User’s Class/Module Class/Module Example Object String Kernel JSON ActiveSupport MyAppUser Root Namespace 🔒 🔒 🔒 Main
 Namespace ✅ ✅ ✅ ✅ Namespace
 A ✅ ✅ ✅ Namespace
 B ✅ ✅ 🔒 classext read only CoW Read

Slide 35

Slide 35 text

Where to go with Namespace in the future?

Slide 36

Slide 36 text

Where to go with Namespace in the future? JUST IDEAS, 
 NOT IMPLEMENTED YET

Slide 37

Slide 37 text

Where to go with Namespace in the future? Modular-monolith(-ish) deployment
 Goodbye Dependency hell
 Safe library loading: “Packages”

Slide 38

Slide 38 text

Modular-Monolith(-ish) Deployment Apps deployed on a (possible) app server • Applications server based on Namespace • namespace per app • multiple apps are mounted using namespace • 2 or more applications on a single tenant (process) • Without con fl icts/collisions by namespace • Especially for development without containers on laptops App Server Namespace Web app Request
 Response Routing

Slide 39

Slide 39 text

Namespace Goodbye Dependency Hell With (possible) Bundler integration • One is in namespace If there is a dependency con fl ict • Your apps can be deployed before the gem’s update! • IMPORTANT: • We MUST keep the “healthy, updated” rubygems society • How to avoid moral hazard? App C ver 1 C ver 2 A B NEED DISCUSSIONS

Slide 40

Slide 40 text

“Packages” API (tentative) All libraries are required in namespace! (really?) • Add a method to require gem as package, with implicit namespace p1 = require_package(‘my-awesome-client’) MyAwesomeClient = p1.export(:MyAwesomeClient) • Optional: default exports (in gemspec?) require_package ‘my-awesome-client’ MyAwesomeClient #=> NS::MyAwesomeClient • Optional: export-as require_package ‘my-awesome-client’, as: :MAClient MAClient #=> NS::MyAwesomeClient NEED DISCUSSIONS

Slide 41

Slide 41 text

When can we use Namespace?

Slide 42

Slide 42 text

When can we use Namespace? 🤔

Slide 43

Slide 43 text

When can we use Namespace? Still in development - Stay tuned! Thank you for listening!