Slide 1

Slide 1 text

Rapid development of enterprise web apps with Netzke Max Gorin (@uptomax)

Slide 2

Slide 2 text

Max Gorin author and maintainer of Netzke on Rails since 2007 nomad since 2008 Dvorak, vim, geekery, speaking, mountains

Slide 3

Slide 3 text

Today's talk is about building web apps

Slide 4

Slide 4 text

Not apps that look like this

Slide 5

Slide 5 text

... but rather like this

Slide 6

Slide 6 text

... or like this

Slide 7

Slide 7 text

eval ?

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

Enterprise apps complex data complex workflows complex GUI

Slide 10

Slide 10 text

Challenges hundreds of data models very comlpex views monstrous monolitic client side decoupled client and server code lack of best practices

Slide 11

Slide 11 text

Few of us deal with those but those who do - are in pain

Slide 12

Slide 12 text

I'm here to ease the pain

Slide 13

Slide 13 text

Let's have a closer look

Slide 14

Slide 14 text

Repeated GUI elements

Slide 15

Slide 15 text

Repeated GUI elements

Slide 16

Slide 16 text

Repeated GUI elements

Slide 17

Slide 17 text

... and most probably more

Slide 18

Slide 18 text

Devide and conquer!

Slide 19

Slide 19 text

Modular GUI development old proven concept used for building complex apps does Rails cooperate? and Cells lack of consistent front-end lack of pre-built components

Slide 20

Slide 20 text

Netzke client-server GUI components for web

Slide 21

Slide 21 text

Netzke component

Slide 22

Slide 22 text

Sencha Ext JS

Slide 23

Slide 23 text

Why Ext JS consistent, themable look tons of feature-rich components programmable views

Slide 24

Slide 24 text

Our arms reusability extensibility (OOP) modular development debugging and testing composability dynamic loading

Slide 25

Slide 25 text

Our score? MAINTAINABLE CODE

Slide 26

Slide 26 text

Floralogic app

Slide 27

Slide 27 text

Cargologic

Slide 28

Slide 28 text

Order flow

Slide 29

Slide 29 text

Roles

Slide 30

Slide 30 text

Models and associations

Slide 31

Slide 31 text

Let's see how Netzke can help

Slide 32

Slide 32 text

Everest Region, Nepal, ~5300m

Slide 33

Slide 33 text

Reusability

Slide 34

Slide 34 text

Models

Slide 35

Slide 35 text

Contacts class Contacts < Netzke::Basepack::Grid def configure(c) super c.model = "Contact" end end

Slide 36

Slide 36 text

Netzke::Basepack::Grid CRUD pagination sorting filtering association support on-the-fly column configuration and more

Slide 37

Slide 37 text

A component is worth nothing ...unless it is configurable and extendable

Slide 38

Slide 38 text

Setting data model class Contacts < Netzke::Basepack::Grid def configure(c) super c.model = "Contact" end end •◦◦

Slide 39

Slide 39 text

Setting data model class Carriers < Netzke::Basepack::Grid def configure(c) super c.model = "Carrier" end end ◦•◦

Slide 40

Slide 40 text

Setting data model class PackingTypes < Netzke::Basepack::Grid def configure(c) super c.model = "PackingType" end end ◦◦•

Slide 41

Slide 41 text

Netzke::Basepack::Grid configuration model columns permissions scope strong attributes and more

Slide 42

Slide 42 text

Our arms reusability ✓ extensibility (OOP) modular development composability dynamic loading

Slide 43

Slide 43 text

Extensibility

Slide 44

Slide 44 text

Netzke component is Ruby class

Slide 45

Slide 45 text

Duplication class Contacts < Netzke::Basepack::Grid def configure(c) super c.model = "Contact" end end class Carriers < Netzke::Basepack::Grid def configure(c) super c.model = "Carrier" end end class PackingTypes < Netzke::Basepack::Grid def configure(c) super c.model = "PackingType" end end

Slide 46

Slide 46 text

Better class GridBase < Netzke::Basepack::Grid def configure(c) super c.model = self.class.name.singularize end end # Now: class Contacts < GridBase end class Carriers < GridBase end class PackingTypes < GridBase end # etc

Slide 47

Slide 47 text

Shared changes class GridBase < Netzke::Basepack::Grid # hide the created_at and updated_at columns column :created_at do |c| c.excluded = true end column :updated_at do |c| c.excluded = true end def configure(c) super c.model = self.class.name.singularize end end

Slide 48

Slide 48 text

Nothing new to you you are Ruby developers! what about the client side?

Slide 49

Slide 49 text

Shipments

Slide 50

Slide 50 text

Shipments

Slide 51

Slide 51 text

Code structure floralogic/ app/ components/ shipments/ grid.rb <--- server code  

Slide 52

Slide 52 text

Code structure floralogic/ app/ components/ shipments/ grid.rb <--- server code grid/ javascripts/ grid.js <--- client code

Slide 53

Slide 53 text

grid.js { initComponent: function(){ this.features = this.features || []; this.features.push({ ftype: 'grouping' }); this.callParent(); } }

Slide 54

Slide 54 text

What goes to JS overrides event handlers any client-side logic more on this in a few minutes

Slide 55

Slide 55 text

Extending with Ruby mixins attachment management for orders and shipments

Slide 56

Slide 56 text

class Shipments::Grid < GridBase include Floralogic::Netzke::Attachments # ... end

Slide 57

Slide 57 text

class Shipments::Grid < GridBase include Floralogic::Netzke::Attachments # ... end

Slide 58

Slide 58 text

class Shipments::Grid < GridBase include Floralogic::Netzke::Attachments # ... end

Slide 59

Slide 59 text

class Shipments::Grid < GridBase include Floralogic::Netzke::Attachments # ... end

Slide 60

Slide 60 text

Our arms reusability ✓ extensibility (OOP) ✓ modular development composability dynamic loading

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

Modular development

Slide 64

Slide 64 text

Floralogic app

Slide 65

Slide 65 text

Floralogic app

Slide 66

Slide 66 text

Filters in Orders::Grid

Slide 67

Slide 67 text

Tests first!

Slide 68

Slide 68 text

Testing code structure floralogic/ spec/ mocha/ fixtures/ orders/ grid.rb <-- fixtures for Orders::Grid specs orders/ grid.js.coffee <-- Orders::Grid specs support/ ... <-- various helpers in CoffeeScript mocha_spec.rb <-- runs all specs from mocha/

Slide 69

Slide 69 text

Fixtures seller1 = FactoryGirl.create :seller, short_name: 'One' seller2 = FactoryGirl.create :seller, short_name: 'Two' cargo1 = FactoryGirl.create :cargo_type, name: 'CARGO ONE' cargo2 = FactoryGirl.create :cargo_type, name: 'CARGO TWO' FactoryGirl.create :order, seller: seller1, cargo_type: cargo1 FactoryGirl.create :order, seller: seller1, cargo_type: cargo2 FactoryGirl.create :order, seller: seller2, cargo_type: cargo1 # ...

Slide 70

Slide 70 text

Mocha specs describe 'Orders::Grid', -> it 'searches by seller', (done) -> wait -> expect(gridCount('Orders')).to.eql 5 select 'One', from: combo('seller_id') wait -> expect(gridCount('Orders')).to.eql 3 select 'Two', from: combo('seller_id') wait -> expect(gridCount('Orders')).to.eql 2 done()

Slide 71

Slide 71 text

Running specs

Slide 72

Slide 72 text

Our arms reusability ✓ extensibility (OOP) ✓ modular development ✓ composability dynamic loading

Slide 73

Slide 73 text

Composability

Slide 74

Slide 74 text

We've seen how to split things apart

Slide 75

Slide 75 text

Now let's see how to put them together

Slide 76

Slide 76 text

Composability in Floralogic

Slide 77

Slide 77 text

Orders::Grid nested in...

Slide 78

Slide 78 text

ShipmentsAndOrders nested in...

Slide 79

Slide 79 text

Workspace nested in...

Slide 80

Slide 80 text

Application

Slide 81

Slide 81 text

ShipmentsAndOrders

Slide 82

Slide 82 text

ShipmentsAndOrders component one-to-many relationship

Slide 83

Slide 83 text

ShipmentsAndOrders component

Slide 84

Slide 84 text

ShipmentsAndOrders: nesting class ShipmentsAndOrders < Netzke::Base js_configure do |c| c.layout = :border end component :shipments do |c| c.klass = Shipments::Grid c.region = :center end component :orders do |c| c.klass = Orders::Grid c.region = :south c.height = 300 end def configure(c) super c.items = [:shipments, :orders] end end

Slide 85

Slide 85 text

Client-side code initComponent: function(){ this.callParent(); var shipments = this.netzkeGetComponent('shipments'), orders = this.netzkeGetComponent('orders'); shipments.on('itemclick', function(view, record){ // call endpoint this.serverSelectShipment(record.get('id')); orders.getStore().load(); }, this); }

Slide 86

Slide 86 text

Select shipment at server class ShipmentsAndOrders < Netzke::Base endpoint :server_select_shipment do |id, this| # dept: authorization component_session[:selected_shipment_id] = id end component :orders do |c| c.klass = Orders::Grid c.shipment_id = component_session[:selected_shipment_id] c.region = :south c.height = 300 end # ... end

Slide 87

Slide 87 text

Orders::Grid module Orders class Grid < GridBase def configure(c) super c.model = "Order" if c.shipment_id c.scope = { shipment_id: c.shipment_id } c.strong_default_attrs = { shipment_id: c.shipment_id } end end # ... end end

Slide 88

Slide 88 text

Notes on composability nesting components is easy by doing it we get new components nested doesn't always mean visible we can show components on demand however...

Slide 89

Slide 89 text

"Complex" app

Slide 90

Slide 90 text

An enterprise app can have hundreds of models and even a bigger number of components

Slide 91

Slide 91 text

Loading them all in one go can be costly

Slide 92

Slide 92 text

Our arms reusability ✓ extensibility (OOP) ✓ modular development ✓ composability ✓ dynamic loading

Slide 93

Slide 93 text

Dynamic loading

Slide 94

Slide 94 text

class Shipments::Grid < GridBase include Floralogic::Netzke::Attachments # ... end

Slide 95

Slide 95 text

Dynamic loading server side class Shipments::Grid < GridBase component :attachment_window do |c| c.klass = Attachment::Window end # ... end

Slide 96

Slide 96 text

Dynamic loading client side onManageAttachments: function(){ var row = this.getSelectionModel().selected.first(); if (row) { this.netzkeLoadComponent('attachment_window', { clientConfig: { id: row.get('id') }, callback: function(w){ w.show(); } }); } }

Slide 97

Slide 97 text

Conclusion

Slide 98

Slide 98 text

Powerful techniques reusability ✓ extensibility (OOP) ✓ modular development ✓ composability ✓ dynamic loading ✓ JS encapsulation

Slide 99

Slide 99 text

Final notes Netzke component != data grid use Netkze Core to build any reusable GUI element that needs to talk to the server forms, trees, dynamic layouts with persistence, photo galeries, charts, etc

Slide 100

Slide 100 text

I love building things with Netzke

Slide 101

Slide 101 text

"If I had to develop a webapp like that, I would try your framework." -- Matz

Slide 102

Slide 102 text

Thanks! @uptomax @netzke

Slide 103

Slide 103 text

No content