Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Patience and the right tools – ways to approach...
Search
stefan judis
February 08, 2018
Technology
700
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Patience and the right tools – ways to approach content modelling
stefan judis
February 08, 2018
More Decks by stefan judis
See All by stefan judis
Back to boring (part 2)
stefanjudis
0
380
Playwright can do this?
stefanjudis
0
260
Things you should know about Frontend Development in 2022
stefanjudis
0
570
Throw yourself out there for fun and profit
stefanjudis
0
140
Back to Boring
stefanjudis
1
540
Wanna scale up? Make sure your CMS is ready for it!
stefanjudis
0
290
Did we(b development) lose the right direction?
stefanjudis
6
2.2k
Regular expressions – my secret love
stefanjudis
1
1.1k
Write a Function
stefanjudis
0
630
Other Decks in Technology
See All in Technology
推論の観測、できていますか? 〜 Google Cloud Gemini Enterprise Agent Platformで 3つの Gemini モデルを実測して踏んだ、評価の罠 〜
shukob
PRO
0
150
AI-DLCって実際どう? 〜聞きたいこと全部聞いてみる〜
news_it_enj
0
220
データエンジニアリングワークショップ:Auto LoaderとSparkで学ぶデータパイプライン構築
databricksjapan
PRO
0
150
リージョンの壁を越える、 ちょっと変わったAWSサービスの話
falken
PRO
0
240
AIで実装は速くなった。なのにプロダクトは速くならない。職能の壁を越えて価値のフローを設計する
nwiizo
6
7k
『止めない』を設計する — 制約の中で、事業の根幹を支える判断
hiroyaterui
0
190
なぜSRE・セキュリティは評価されないのか?守りの組織を事業成長エンジンに変えた実践
cscengineer
PRO
3
2.2k
データエンジニアの困りごとをDevinと一緒に解消する
10xinc
2
820
grill-me(grilling):AI駆動開発を超助けてくれるSkill / grill me
mathbullet
0
100
いま、生成AIにKaggleをどこまで 任せられるか — ROGIIコンペでの進め方とTips
k951286
3
1.4k
コスト最適化の「めんどくさい」を AWS FinOps Agent でチョット楽にする
classmethod_kaz
0
170
AIで開発は速くなったのに、なぜ現場は楽にならないのか 〜あなたの組織のボトルネックを突き止めるワークショップ〜
jacopen
1
260
Featured
See All Featured
Writing Fast Ruby
sferik
630
63k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.9k
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
260
Building Flexible Design Systems
yeseniaperezcruz
330
41k
SEO for Brand Visibility & Recognition
aleyda
0
4.7k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
520
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.6k
Accessibility Awareness
sabderemane
1
200
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
270
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
4.6k
Product Roadmaps are Hard
iamctodd
55
13k
Transcript
Patience and the right tools @stefanjudis Ways to approach content
modelling
Stefan Judis Frontend Developer, Occasional Teacher, Meetup Organizer ❤ Open
Source, Performance and Accessibility ❤ @stefanjudis
Where we come from
Karen McGrane I don’t necessarily know where this content is
going to live. I don’t know how it’s going to be used in the future. But, I do know that I have to create lots of flexible content that has metadata attached to it because I know it’s going to be reused in different places. “
None
None
It's like Lego
NOBODY(!) GETS IT RIGHT THE FIRST TIME...
share Share & reuse
github.com/joshhebb/angularjs-contentful-starter
None
www.npmjs.com/package/contentful-import www.npmjs.com/package/contentful-export
It's just code Setting up a space is quickly done
When you know how...
I believe in tooling and defaults!
Eat your own dog food
None
USEFUL FOR ANYONE?
Share content models?
None
www.contentfulcommunity.com MAYBE HERE?
Analyse
None
www.npmjs.com/package/contentful-graph
None
YOUR CONTENT MODEL VISUALISED.
None
None
CLI is great, but there is more
contentful-graph.yaraslav.com/
Evolve
Clean up time
www.npmjs.com/package/contentful-migration-cli
MIGRATION CLI CONTENT TYPE OPERATIONS Create a content type 01
02 03 04 05 Delete a content type Edit a content type Create/edit/delete fields Change a field ID
FIELDS TO DELETE
Drop fields module.exports = function (migration) { const event =
migration.editContentType('event') const project = migration.editContentType('project') }
module.exports = function (migration) { const event = migration.editContentType('event') event.deleteField('hotel')
event.deleteField('venue') const project = migration.editContentType('project') project.deleteField('screenshot') } Drop fields
None
FIELDS TO RENAME VS
module.exports = function (migration) { const tilPost = migration.editContentType('tilPost') }
Change field ID
module.exports = function (migration) { const tilPost = migration.editContentType('tilPost') tilPost.changeFieldId('categories',
'tags') tilPost.editField('tags', { name: 'Tags' }) tilPost.moveField('tags').afterField('date') } Change field ID
None
FRONTTRENDS 2017 COUNTRY : PL CITY : WARSAW ... FRONTTRENDS
2018 COUNTRY : PL CITY : WARSAW ... DERIVE ENTRIES AND LINK
FT COUNTRY: PL CITY : WARSAW FRONTTRENDS 2017 COUNTRY :
PL CITY : WARSAW ... FRONTTRENDS 2018 COUNTRY : PL CITY : WARSAW ... DERIVE ENTRIES AND LINK
FRONTTRENDS 2017 CONFERENCE : FT ... FRONTTRENDS 2018 CONFERENCE :
FT ... FT COUNTRY: PL CITY : WARSAW DERIVE ENTRIES AND LINK
A looong manual nightshift
No way!
repetetive error-prone not scalable MANUAL CONTENT MODEL CHANGES ARE NOT
THE SOLUTION
Transform an entry in place 01 02 Derive an entry
from another MIGRATION CLI CONTENT TRANSFORMATIONS
module.exports = function (migration) { const conference = migration.createContentType('conference') .name('Conference/Meetup')
.displayField('name') conference.createField('name') .type('Symbol') .required(true) .name('Conference/Meetup name') conference.createField('country') .type('Symbol') .required(true) .name('Country Code') conference.createField('city') .type('Symbol') .required(true) .name('City') Derive entries and link
.name('Country Code') conference.createField('city') .type('Symbol') .required(true) .name('City') const event = migration.editContentType('event')
event.createField('conference') .name('Conference') .type('Link') .linkType('Entry') .validations([ { "linkContentType": ['conference'] } ]) Derive entries and link
]) migration.deriveLinkedEntries({ contentType: 'event', from: ['name', 'country', 'city'], toReferenceField: 'conference',
derivedContentType: 'conference', derivedFields: ['name', 'country', 'city'], identityKey: async (from) => { return getId(from.name['en-US']) }, deriveEntryForLocale: async (inputFields, locale) => { return { name: inputFields.name[locale].replace(/\s(\d{2,4}|#\d+)/g, ''), country: inputFields.country[locale] || 'N/A', city: inputFields.city[locale] || 'N/A' } } }) Derive entries and link
]) migration.deriveLinkedEntries({ contentType: 'event', from: ['name', 'country', 'city'], toReferenceField: 'conference',
derivedContentType: 'conference', derivedFields: ['name', 'country', 'city'], identityKey: async (from) => { return getId(from.name['en-US']) }, deriveEntryForLocale: async (inputFields, locale) => { return { name: inputFields.name[locale].replace(/\s(\d{2,4}|#\d+)/g, ''), country: inputFields.country[locale] || 'N/A', city: inputFields.city[locale] || 'N/A' } } }) Derive entries and link
]) migration.deriveLinkedEntries({ contentType: 'event', from: ['name', 'country', 'city'], toReferenceField: 'conference',
derivedContentType: 'conference', derivedFields: ['name', 'country', 'city'], identityKey: async (from) => { return getId(from.name['en-US']) }, deriveEntryForLocale: async (inputFields, locale) => { return { name: inputFields.name[locale].replace(/\s(\d{2,4}|#\d+)/g, ''), country: inputFields.country[locale] || 'N/A', city: inputFields.city[locale] || 'N/A' } } }) Derive entries and link
]) migration.deriveLinkedEntries({ contentType: 'event', from: ['name', 'country', 'city'], toReferenceField: 'conference',
derivedContentType: 'conference', derivedFields: ['name', 'country', 'city'], identityKey: async (from) => { return getId(from.name['en-US']) }, deriveEntryForLocale: async (inputFields, locale) => { return { name: inputFields.name[locale].replace(/\s(\d{2,4}|#\d+)/g, ''), country: inputFields.country[locale] || 'N/A', city: inputFields.city[locale] || 'N/A' } } }) Derive entries and link
} } }) event.moveField('conference').afterField('name') event.deleteField('country') event.deleteField('city') } Derive entries and
link
None
module.exports = function (migration) { const conference = migration.createContentType('conference') .name('Conference/Meetup')
.displayField('name') conference.createField('name').type('Symbol').required(true).name('Conference/Meetup name') conference.createField('country').type('Symbol').required(true).name('Country Code') conference.createField('city').type('Symbol').required(true).name('City') const event = migration.editContentType('event') event.createField('conference') .name('Conference') .type('Link') .linkType('Entry') .validations([ { "linkContentType": ['conference'] } ]) migration.deriveLinkedEntries({ contentType: 'event', from: ['name', 'country', 'city'], toReferenceField: 'conference', derivedContentType: 'conference', derivedFields: ['name', 'country', 'city'], identityKey: async (from) => { return from.name['en-US'] // remove year .replace(/\s(\d{2,4}|#\d+)/g, '') // clear spaces .replace(/\s/g, '-') // clear "weird characters" .replace(/(,|\/|\\|:|\.|\(|\))/g, '') .toLowerCase() }, deriveEntryForLocale: async (inputFields, locale) => { return { name: inputFields.name[locale].replace(/\s(\d{2,4}|#\d+)/g, ''), country: inputFields.country[locale] || 'N/A', city: inputFields.city[locale] || 'N/A' } } }) event.moveField('conference').afterField('name') event.deleteField('country') event.deleteField('city') } LOC 48 REQUESTS 382 ENTRIES CREATED 88 ENTRIES UPDATED 96
MIGRATION CLI ADVANTAGES Repeatable 01 02 03 04 Can be
kept in VC Includes sanity checks Perfect for CI
NOBODY(!) GETS IT RIGHT THE FIRST TIME...
61 WAYS TO SURVIVE SHARE & REUSE ANALYSE EVOLVE
with the right tools...
Thanks. @stefanjudis Slides ctfl.io/content-modelling-is-tricky Article ctfl.io/content-modelling-is-tricky-article