Slide 1

Slide 1 text

Content integration at Bookmate Evgeny Li exAspArk

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

• 3 million users • 600 publishers • 1000 new uploaded books per day

Slide 4

Slide 4 text

Simplified architecture Publisher Metadata XML,CSV Book EPUB, FB2 Cover JPEG, PNG Bookmate Source Clients

Slide 5

Slide 5 text

Metadata http://www.editeur.org/83/Overview ONIX (ONline Information eXchange) is an XML-based international standard for representing and communicating book industry product information in electronic form.

Slide 6

Slide 6 text

How many people in Russia use ONIX http://25.media.tumblr.com/tumblr_m784a1326G1rb3v0jo1_250.gif

Slide 7

Slide 7 text

ONIX sample                  20131202T192459          42          EUR          ...                      03          01                        15              9781824302123                                                  1                  A01                  David  Herbert  Lawrence                                              10                  FIC000000                            ...                                                    11                  00                  20101028                                              06                                        AS  CA  GU  MP  PH  PR  US  VI                                              ...                    ...

Slide 8

Slide 8 text

Specification is about 500 pages long http://1.bp.blogspot.com/-6-PaY1EWEK0/UnZt-TRK5QI/AAAAAAAAOnU/hSTQA3YNNxQ/s1600/chandler-bing-book.gif

Slide 9

Slide 9 text

• ONIX 2.1 – https://github.com/yob/onix (not maintained) • ONIX 3.0 – https://github.com/immateriel/im_onix RubyGems

Slide 10

Slide 10 text

Gems use the same names for modules & classes https://media.giphy.com/media/ToMjGpnXBTw7vnokxhu/giphy.gif

Slide 11

Slide 11 text

RubyGems • ONIX 2.1 – https://github.com/exAspArk/onix2 (fork) • ONIX 3.0 – https://github.com/immateriel/im_onix

Slide 12

Slide 12 text

• Easy to start • Open source • No ubiquitous language • Extra data abstractions https://en.wikipedia.org/wiki/Domain-driven_design

Slide 13

Slide 13 text

ONIX 2.1 Book metadata ONIX 3.0 onix2 im_onix onix2 adapter onix3 adapter Gems Application XML

Slide 14

Slide 14 text

Simple Made Easy http://www.infoq.com/presentations/Simple-Made-Easy Simple Easy

Slide 15

Slide 15 text

ONIX 2.1 Book metadata ONIX 3.0 onix2 im_onix onix2 adapter onix3 adapter Gems Application XML Why to use this extra layer?

Slide 16

Slide 16 text

ONIX 2.1 Book metadata ONIX 3.0 onix2 adapter onix3 adapter Application XML

Slide 17

Slide 17 text

https://github.com/exAspArk/better_struct

Slide 18

Slide 18 text

BetterStruct example BetterStruct.new(nil)  ==  BetterStruct.new(nil).no_undefined_method_error   #  =>  true  

Slide 19

Slide 19 text

BetterStruct example BetterStruct.new(nil)  ==  BetterStruct.new(nil).no_undefined_method_error   #  =>  true   BetterStruct.new(nil)  ==  BetterStruct.new(nil).maybe.monad   #  =>  true  

Slide 20

Slide 20 text

BetterStruct example BetterStruct.new(nil)  ==  BetterStruct.new(nil).no_undefined_method_error   #  =>  true   BetterStruct.new(nil)  ==  BetterStruct.new(nil).maybe.monad   #  =>  true   like_open_struct  =  BetterStruct.new({  title:  "Fifty  Shades  of  Grey"  })   like_open_struct.title.value   #  =>  "Fifty  Shades  of  Grey"  

Slide 21

Slide 21 text

BetterStruct example BetterStruct.new(nil)  ==  BetterStruct.new(nil).no_undefined_method_error   #  =>  true   BetterStruct.new(nil)  ==  BetterStruct.new(nil).maybe.monad   #  =>  true   like_open_struct  =  BetterStruct.new({  title:  "Fifty  Shades  of  Grey"  })   like_open_struct.title.value   #  =>  "Fifty  Shades  of  Grey"   like_open_struct.title.sub("Fifty",  "No").first.value   #  =>  "N"

Slide 22

Slide 22 text

ONIX example                                                                        Atlas  Shrugged                                                  

Slide 23

Slide 23 text

class  ONIX::V3::ProductAdapter      def  initialize(product)          @product  =  BetterStruct.new(product)      end      def  title          @product.descriptive_detail.title_detail.title_element.title_text.value      end   end                                                                        Atlas  Shrugged                                                   ONIX example

Slide 24

Slide 24 text

class  ONIX::V3::ProductAdapter      def  initialize(product)          @product  =  BetterStruct.new(product)      end      def  title          @product.descriptive_detail.title_detail.title_element.title_text.value      end   end   ONIX example xml  =  "Atlas  Shrugged TitleText>"  

Slide 25

Slide 25 text

class  ONIX::V3::ProductAdapter      def  initialize(product)          @product  =  BetterStruct.new(product)      end      def  title          @product.descriptive_detail.title_detail.title_element.title_text.value      end   end   ONIX example https://github.com/savonrb/nori xml  =  "Atlas  Shrugged TitleText>"   product  =  Nori.new.parse(xml)   #  =>  {  "DescriptiveDetail"  =>  {  "TitleDetail"  =>  {  "TitleElement"  =>  {  "TitleText"  =>   "Atlas  Shrugged"  }}}}  

Slide 26

Slide 26 text

class  ONIX::V3::ProductAdapter      def  initialize(product)          @product  =  BetterStruct.new(product)      end      def  title          @product.descriptive_detail.title_detail.title_element.title_text.value      end   end   ONIX example xml  =  "Atlas  Shrugged TitleText>"   product  =  Nori.new.parse(xml)   #  =>  {  "DescriptiveDetail"  =>  {  "TitleDetail"  =>  {  "TitleElement"  =>  {  "TitleText"  =>   "Atlas  Shrugged"  }}}}   product_adapter  =  ONIX::V3::ProductAdapter.new(product)   product_adapter.title   #  =>  "Atlas  Shrugged" https://github.com/savonrb/nori

Slide 27

Slide 27 text

product   #  =>  {  "DescriptiveDetail"  =>  {  "TitleDetail"  =>  {  "TitleElement"  =>  {  "TitleText"  =>   "Atlas  Shrugged"  }}}}   BetterStruct.new(product).descriptive_detail.title_detail.title_element.title_text.value   ONIX example

Slide 28

Slide 28 text

product   #  =>  {  "DescriptiveDetail"  =>  {  "TitleDetail"  =>  {  "TitleElement"  =>  {  "TitleText"  =>   "Atlas  Shrugged"  }}}}   BetterStruct.new(product).descriptive_detail.title_detail.title_element.title_text.value   product["DescriptiveDetail"]["TitleDetail"]["TitleElement"]["TitleText"]   ONIX example

Slide 29

Slide 29 text

product   #  =>  {  "DescriptiveDetail"  =>  {  "TitleDetail"  =>  {  "TitleElement"  =>  {  "TitleText"  =>   "Atlas  Shrugged"  }}}}   BetterStruct.new(product).descriptive_detail.title_detail.title_element.title_text.value   product["DescriptiveDetail"]  &&        product["DescriptiveDetail"]["TitleDetail"]  &&        product["DescriptiveDetail"]["TitleDetail"]["TitleElement"]  &&      product["DescriptiveDetail"]["TitleDetail"]["TitleElement"]["TitleText"]   ONIX example

Slide 30

Slide 30 text

product   #  =>  {  "DescriptiveDetail"  =>  {  "TitleDetail"  =>  {  "TitleElement"  =>  {  "TitleText"  =>   "Atlas  Shrugged"  }}}}   BetterStruct.new(product).descriptive_detail.title_detail.title_element.title_text.value   product["DescriptiveDetail"]  &&        product["DescriptiveDetail"]["TitleDetail"]  &&        product["DescriptiveDetail"]["TitleDetail"]["TitleElement"]  &&      product["DescriptiveDetail"]["TitleDetail"]["TitleElement"]["TitleText"]   product[“DescriptiveDetail”].      try(:[],  “TitleDetail").      try(:[],  “TitleElement").      try(:[],  "TitleText")   ONIX example

Slide 31

Slide 31 text

product   #  =>  {  "DescriptiveDetail"  =>  {  "TitleDetail"  =>  {  "TitleElement"  =>  {  "TitleText"  =>   "Atlas  Shrugged"  }}}}   BetterStruct.new(product).descriptive_detail.title_detail.title_element.title_text.value   product["DescriptiveDetail"]  &&        product["DescriptiveDetail"]["TitleDetail"]  &&        product["DescriptiveDetail"]["TitleDetail"]["TitleElement"]  &&      product["DescriptiveDetail"]["TitleDetail"]["TitleElement"]["TitleText"]   product[“DescriptiveDetail”].      try(:[],  “TitleDetail").      try(:[],  “TitleElement").      try(:[],  "TitleText")   product["DescriptiveDetail"]["TitleDetail"]["TitleElement"]["TitleText"]  rescue  nil ONIX example

Slide 32

Slide 32 text

CSV example Título completo Año publicación Nombre 1 eISBN epub Programa de transición 2008 Trotsky, León 9781449262123 filepath  =  "spanish_publisher.csv"   books  =  CSV.parse(File.read(filepath),  headers:  true)   book_data  =  BetterStruct.new(books.first.to_h)  

Slide 33

Slide 33 text

CSV example Título completo Año publicación Nombre 1 eISBN epub Programa de transición 2008 Trotsky, León 9781449262123 filepath  =  "spanish_publisher.csv"   books  =  CSV.parse(File.read(filepath),  headers:  true)   book_data  =  BetterStruct.new(books.first.to_h)   book_data.titulo_completo.value   #  =>  "Programa  de  transición"  

Slide 34

Slide 34 text

CSV example Título completo Año publicación Nombre 1 eISBN epub Programa de transición 2008 Trotsky, León 9781449262123 filepath  =  "spanish_publisher.csv"   books  =  CSV.parse(File.read(filepath),  headers:  true)   book_data  =  BetterStruct.new(books.first.to_h)   book_data.titulo_completo.value   #  =>  "Programa  de  transición"   book_data.ano_publicacion.value   #  =>  "2008"  

Slide 35

Slide 35 text

CSV example Título completo Año publicación Nombre 1 eISBN epub Programa de transición 2008 Trotsky, León 9781449262123 filepath  =  "spanish_publisher.csv"   books  =  CSV.parse(File.read(filepath),  headers:  true)   book_data  =  BetterStruct.new(books.first.to_h)   book_data.titulo_completo.value   #  =>  "Programa  de  transición"   book_data.ano_publicacion.value   #  =>  "2008"   book_data.nombre_1.split(",  ").reverse.join("  ").value   #  =>  "León  Trotsky"  

Slide 36

Slide 36 text

CSV example Título completo Año publicación Nombre 1 eISBN epub Programa de transición 2008 Trotsky, León 9781449262123 filepath  =  "spanish_publisher.csv"   books  =  CSV.parse(File.read(filepath),  headers:  true)   book_data  =  BetterStruct.new(books.first.to_h)   book_data.titulo_completo.value   #  =>  "Programa  de  transición"   book_data.ano_publicacion.value   #  =>  "2008"   book_data.nombre_1.split(",  ").reverse.join("  ").value   #  =>  "León  Trotsky"   book_data.e_isbn_epub.value   #  =>  "9781449262123"

Slide 37

Slide 37 text

Conclusion Don’t ruin information behind a micro-language, i.e. a class with information-specific methods Rich Hickey

Slide 38

Slide 38 text

Thank you!