Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rapid development of enterprise web apps with Netzke

Rapid development of enterprise web apps with Netzke

RubyKaigi 2013, Tokyo: http://rubykaigi.org/2013/talk/S34

D1c04abb992f6c5369891276c206a999?s=128

Max Gorin

June 01, 2013
Tweet

More Decks by Max Gorin

Other Decks in Technology

Transcript

  1. Rapid development of enterprise web apps with Netzke Max Gorin

    (@uptomax)
  2. Max Gorin author and maintainer of Netzke on Rails since

    2007 nomad since 2008 Dvorak, vim, geekery, speaking, mountains
  3. Today's talk is about building web apps

  4. Not apps that look like this

  5. ... but rather like this

  6. ... or like this

  7. eval ?

  8. None
  9. Enterprise apps complex data complex workflows complex GUI

  10. Challenges hundreds of data models very comlpex views monstrous monolitic

    client side decoupled client and server code lack of best practices
  11. Few of us deal with those but those who do

    - are in pain
  12. I'm here to ease the pain

  13. Let's have a closer look

  14. Repeated GUI elements

  15. Repeated GUI elements

  16. Repeated GUI elements

  17. ... and most probably more

  18. Devide and conquer!

  19. 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
  20. Netzke client-server GUI components for web

  21. Netzke component

  22. Sencha Ext JS

  23. Why Ext JS consistent, themable look tons of feature-rich components

    programmable views
  24. Our arms reusability extensibility (OOP) modular development debugging and testing

    composability dynamic loading
  25. Our score? MAINTAINABLE CODE

  26. Floralogic app

  27. Cargologic

  28. Order flow

  29. Roles

  30. Models and associations

  31. Let's see how Netzke can help

  32. Everest Region, Nepal, ~5300m

  33. Reusability

  34. Models

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

    "Contact" end end
  36. Netzke::Basepack::Grid CRUD pagination sorting filtering association support on-the-fly column configuration

    and more
  37. A component is worth nothing ...unless it is configurable and

    extendable
  38. Setting data model class Contacts < Netzke::Basepack::Grid def configure(c) super

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

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

    c.model = "PackingType" end end ◦◦•
  41. Netzke::Basepack::Grid configuration model columns permissions scope strong attributes and more

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

    loading
  43. Extensibility

  44. Netzke component is Ruby class

  45. 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
  46. 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
  47. 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
  48. Nothing new to you you are Ruby developers! what about

    the client side?
  49. Shipments

  50. Shipments

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

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

    grid/ javascripts/ grid.js <--- client code
  53. grid.js { initComponent: function(){ this.features = this.features || []; this.features.push({

    ftype: 'grouping' }); this.callParent(); } }
  54. What goes to JS overrides event handlers any client-side logic

    more on this in a few minutes
  55. Extending with Ruby mixins attachment management for orders and shipments

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

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

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

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

  60. Our arms reusability ✓ extensibility (OOP) ✓ modular development composability

    dynamic loading
  61. None
  62. None
  63. Modular development

  64. Floralogic app

  65. Floralogic app

  66. Filters in Orders::Grid

  67. Tests first!

  68. 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/
  69. 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 # ...
  70. 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()
  71. Running specs

  72. Our arms reusability ✓ extensibility (OOP) ✓ modular development ✓

    composability dynamic loading
  73. Composability

  74. We've seen how to split things apart

  75. Now let's see how to put them together

  76. Composability in Floralogic

  77. Orders::Grid nested in...

  78. ShipmentsAndOrders nested in...

  79. Workspace nested in...

  80. Application

  81. ShipmentsAndOrders

  82. ShipmentsAndOrders component one-to-many relationship

  83. ShipmentsAndOrders component

  84. 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
  85. 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); }
  86. 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
  87. 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
  88. 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...
  89. "Complex" app

  90. An enterprise app can have hundreds of models and even

    a bigger number of components
  91. Loading them all in one go can be costly

  92. Our arms reusability ✓ extensibility (OOP) ✓ modular development ✓

    composability ✓ dynamic loading
  93. Dynamic loading

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

  95. Dynamic loading server side class Shipments::Grid < GridBase component :attachment_window

    do |c| c.klass = Attachment::Window end # ... end
  96. 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(); } }); } }
  97. Conclusion

  98. Powerful techniques reusability ✓ extensibility (OOP) ✓ modular development ✓

    composability ✓ dynamic loading ✓ JS encapsulation
  99. 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
  100. I love building things with Netzke

  101. "If I had to develop a webapp like that, I

    would try your framework." -- Matz
  102. Thanks! @uptomax @netzke

  103. None