POPULARITY
Joël and fellow thoughtboter Aji Slater examine the unfamiliar world of Typescript (https://www.typescriptlang.org/) and various ways of working within it's system. They lay out the pros and cons of Typescript over other environments such as Ruby and Elm and discuss their experience of adopting LLM partners to assist in their workflows. Utilising Chat GPT and Claude to verify code and trim down syntax, all while trying to appease the type checker. Discover the little tips, tricks and bad habits they picked up along the way while working with their LLM buddies in an effort to improve efficiency. — Check out Ruby2D (https://www.ruby2d.com) for all your 2D app needs! You can connect with Aji via LinkedIn (https://www.linkedin.com/in/doodlingdev/), or check out some of the topics he's written about over on his thoughtbot blog (https://thoughtbot.com/blog/authors/aji-slater). Your host for this episode has been Joël Quenneville (https://www.linkedin.com/in/joel-quenneville-96b18b58/). If you would like to support the show, head over to our GitHub page (https://github.com/sponsors/thoughtbot), or check out our website (https://bikeshed.thoughtbot.com). Got a question or comment about the show? Why not write to our hosts: hosts@bikeshed.fm This has been a thoughtbot (https://thoughtbot.com/) podcast. Stay up to date by following us on social media - YouTube (https://www.youtube.com/@thoughtbot/streams) - LinkedIn (https://www.linkedin.com/company/150727/) - Mastodon (https://thoughtbot.social/@thoughtbot) - Bluesky (https://bsky.app/profile/thoughtbot.com) © 2025 thoughtbot, inc.
Übersicht PromPerú: https://promperu.de/gastronomie/peruanische-gerichte/peruanische-restaurants-in-deutschland/Falls du gerade aus Peru zurückgekommen bist und weiterhin authentisch peruanisch essen möchtest, oder einfach neugierig auf das beste Ceviche bist und mal etwas Neues ausprobieren möchtest, bist du hier genau richtig!In ganz Deutschland findest du eine Reihe von Restaurants, die peruanische Gerichte anbieten. Oft handelt es sich dabei um lateinamerikanische Restaurants, die auch peruanische Spezialitäten servieren. Ich habe für dich eine Liste zusammengestellt, wo du in Deutschland peruanische Küche genießen kannst. Viele dieser Restaurants habe ich selbst ausprobiert und kann sie aus eigener Erfahrung empfehlen!Ob du in Berlin, München, Hamburg oder einem anderen Ort in Deutschland bist, es gibt sicher ein peruanisches Restaurant in deiner Nähe. Diese Gaststätten bieten häufig eine Auswahl an klassischen Gerichten wie Lomo Saltado, Aji de Gallina und natürlich Ceviche. Entdecke die Vielfalt und den Reichtum der peruanischen Küche direkt hier in Deutschland.
Send us a textHow do visionaries from traditional finance reshape the world of crypto marketing? Tune in as we welcome Aysenur Yükselal Aji, the Vice President of Marketing at Bitstamp, who brings a wealth of knowledge from her fintech and finance background to the crypto realm. Together, we unravel her strategic approach to blending consistency, security, transparency, and simplicity into Bitstamp's brand messaging. With the imminent implementation of MiCA in Europe, Aysenur sheds light on the challenges and opportunities posed by the evolving regulatory landscape, underscoring the necessity for agility and data-driven decision-making amidst market fluctuations and skepticism.Our conversation also brings to the forefront the power of data-driven marketing strategies in fostering customer loyalty and engagement. Discover how Bitstamp crafts its brand trust by segmenting customer data to tailor communications and product offerings. Aysenur shares insights from a successful CRM lifecycle management campaign, where celebrating trading anniversaries has led to heightened customer interaction. We also unpack the intricacies of simplifying complex blockchain concepts, highlighting the impact of the "Proudly Boring" campaign. By focusing on security and regulation, this initiative has significantly boosted customer acquisition and app downloads, proving that sometimes, staying true to one's roots is the real game-changer.This episode was recorded through a Podcastle call on November 22, 2024. Read the blog article and show notes here: https://webdrie.net/navigating-crypto-branding-and-regulations-with-aysenur-yukselal-aji-vp-marketing-at-bitstamp/Discover RYO: the Web3 payment solution making crypto simple and secure for everyone. Featuring an expansive ecosystem with LIFE Wallet, Global Mall, and Japan's first licensed Crypto ATM Network, RYO empowers your financial journey. Awarded 'Best Crypto Solution.' Explore at ryocoin.com
When you think of supermarkets, you probably think more about groceries than AI. This week's guests are helping evolve Tesco into a technology-led organisation driving innovation in the highly competitive grocery space.Head of Product, Aji Bawo and Graduate Software Engineer, Naamua Dodoo join Gareth on this week's episode of TTLP to discuss their experiences joining the biggest supermarket in the UK as a tech graduate. This episode explores the role of Tesco as an employer, the importance of diversity and inclusion within tech, and the key considerations for graduates looking to start a career in the industry. If you're someone who's looking to embark on a career in tech, or a technology leader considering hiring entry level talent, this episode provides incredible insight you won't want to miss!Time stamps· How both Naamua and Aji got into tech (03:00)· What good leadership means to Aji (06:06)· What Naamua looks for in a leader (07:45)· The main technology skills graduates need to know (11:25)· How graduate recruitment has changed at Tesco (23:14)· Is the technology industry becoming more diverse? (33:00)· How Tesco is leveraging AI (42:28)· Will graduates be replaced by AI? (48:40)· Naamua's advice to new graduates (54:02)· Aji's advice to her younger self (54:54) Book recommendations: How Women Rise, Sally Helgesen amazon.co.uk/How-Women-Rise-Habits-Holding/dp/1847942253/ref=sr_1_1?crid=164GS4TGSBHLA&dib=eyJ2IjoiMSJ9.arPA90K8OERoOH18pbxgFCNT4yI7xZTObt3ShCkf4yOu6ELcJ9_kKmmjm7S_kgpOvsXCDOPCFPzbfr-YdkZhZaHw_DJ_TZO4PcQsS3xY_MOXtq_2JmFWNVx-dG_NFSuaIWoAwhR_BGIcsjfVw3rFUS9Mkw--cAxEbMyOTcPG7mk2RoNAZgF8-tHwlVniJh-9cvjjcHryqIuTIaaOU3cgDR2RMT6G2hVeuD7j8ebmGPU.W6MXP5nlQURJdUjCr0QLxNd5JFckjJeldjs5jPfAODE&dib_tag=se&keywords=how+women+rise&qid=1724776577&s=audible&sprefix=how+women+rise%2Caudible%2C81&sr=1-1-catcorrNice Girls Don't Get The Corner Office, Lois. P. Frankel amazon.co.uk/Nice-Girls-Dont-Corner-Office/dp/1455558893/ref=sr_1_1?crid=S29EGCNUWI36&dib=eyJ2IjoiMSJ9.DemEIEROR7o2-ucu3AZavFTXXFmHMxi661IIVRmxnHFB62YF1dD7SlN2YWSoKOvvXwtAhch5D04a36vDqxRzq1MMtPd8GvebQyigSBvLAxy4VY1VcbQ3KHyuA0TS086l3VW--U4nz5AAMkU5SRxQ7VwXrHIkEyOZmqCHKGqjatBagmJZ4sAydkT3QnmijCu_2fRu3a-jN0eBwb4umq7oHNtl1BPe4xUCYr03WFqeMj8.88jZKu3vXEm-RCdDNXOJpx2Uc22lLhT9_c2zuzLUWR8&dib_tag=se&keywords=nice+girls+don%27t+get+the+corner+office&qid=1724776632&sprefix=nice+girls+%2Caps%2C76&sr=8-1
In this episode, the Creeps try Peruvian dishes from Miskycha, located at 139 Conference Center Way Ste. 105, Bridgeport, WV. Open Mon-Sat 11:00 AM - 8:00 PM. Here's what we tried: Roasted chicken and rice with aji pepper sauce, Aji de gallina (Creamy spicy chicken served over potatoes and rice with olive and egg), and a special they were serving to celebrate Fiestas Patrias (Pervuian Independence) - Mazamorra Morada (Cinnamon spiced Purple Corn Pudding with plums) They are highly recommended by the show, this is some of the best food we've ever tried. Main Corpse Seal of Approval. Then, Matt hops up on his soapbox against the allure of serial killer culture, and instead covers the works and life of Sharon Tate, and the life she and her child could have continued to have, had it not been cut short by murderous cultists that Matt would rather no longer continue to name. You have homework at Matt's request: Go watch the movies Eye of the Devil, Fearless Vampire Killers, and Valley of the Dolls. The Creeps also talk about Christmas desserts, movie references, and Jack Palance.
以正念冥想作为展演主题打动了评委和观众,一石激起千层浪!一起来近距离认识一下这位2024WBC釜山世界赛冠军Mikael Jasin吧,听听看一名屡战不败的老选手如何经历7年比赛生涯,终夺桂冠!Mikael的咖啡之旅始于2012年, 在澳大利亚墨尔本担任咖啡师。尽管在墨尔本求学期间, 他的专业与咖啡行业相去甚远, 但仍不妨碍他追求理想的热情。2017年, 他放弃了在墨尔本雇主担保的机会, 以收入锐减的代价回到印尼,加入了号称"咖啡冠军制造所" 的CommonGrounds,以咖啡品控与市场主管的身份重新开始!多年来, 他没有停止参加比赛,在2018和2019年印度尼西亚咖啡师大赛中分别获得第二名;2020年, 终于夺得第一个印度尼西亚咖啡师全国冠军, 并在波士顿举行的世界咖啡师大赛中获得第四名, 这为他在2024年的胜利奠定了基础。作为印尼咖啡面向世界的形象大使, Mikael还致力于提升印度尼西亚咖啡的国际地位。他创办了So So Good Coffee Company和CATUR Coffee Company,通过为咖啡师提供培训, 为咖啡店主提供咨询服务以及与农民合作改进后处理技术,全面提升印度尼西亚咖啡的质量和一致性。聊到将亚洲产区生产的咖啡豆带上国际舞台, 他很真诚地表达了这是每一个身处亚洲生产国的咖啡人们的共同功课!或许, 对Mikael而言, 作为咖啡师的旅程, 在现阶段告一段落,而将印尼咖啡以全新的面貌分享给全世界, 这段旅程才刚刚开始....『本期嘉宾』Mikael Jasin �2024WBC世界咖啡师大赛冠军Co-Founder of So So Good Company Co-Founder of CATUR Coffee Company Co-Founder of Omakafe『本期内容』Table of Contents00:11 开头福利02:16 Mikael打招呼03:02 印尼妈妈在牛奶里加速溶咖啡05:22 在墨大求学,不出意外成为咖啡师09:44 放弃高薪回印尼12:18 加入CommonGrounds14:02 2019年WBC用印尼豆打世界赛19:52 米兰世界赛留有遗憾, 接触正念冥想25:22 现今的WBC到底是比技术, 还是比说故事的能力?28:5 想赢比赛?展演里学问多39:32 教练David和Cole的帮助43:00 Mind-body-soul46:34 植物奶拼牛奶47:50 Aji bourbon不是波旁49:52 人工接种酵母控制发酵51:27 来自日本的杯子53:51 秘鲁圣木Palo santo56:59 越来越多原产地咖啡师收获冠军意义非凡01:00:52 印尼的精品咖啡文化01:03:56 不被理解的印尼咖啡豆01:06:23 成为成功的生豆出口商01:16:01 我们的一点碎碎念本期主播:Yike / Yujia封面图:Echo 摄如果你喜欢我们的节目内容,请记得订阅频道。推荐您在小宇宙App,苹果Podcasts, Spotify,豆瓣播客等泛用性客户端收听我们的节目,你还可以通过喜马拉雅,网易云音乐,QQ音乐,Google podcast等平台收听我们的节目。如果您喜欢我们的内容,请别忘了在小宇宙App给我们留言、点赞,在苹果Podcast给我们五星好评,也请多分享播客给朋友们!如果希望支持我们,可以通过“爱发电”平台打赏:https://afdian.net/a/coffeeplusYYY片尾音乐:God Rest Ye Merry Gentlmen - DJ Williams『留言互动』 小红书:@Coffeeplus播客 @Yujia_66微信公众号:Coffeeplus播客也可以搜索添加微信Fishplus_wx, 记得备注“播客”哦,邀请您进入微信社群~
Richard Just is managing editor for long form for News of the United States and head of the Albritton Journalism Institute's Admissions process. He joins Lisa today in advance of announcing the second (ever) class for the AJI. With a magazine background, Richard takes us into the process of developing and delivering journalism that is not on the usual breaking news track -- rather at the intersection of news and opinion, as he explains. Tune in today to hear more about his role at this amazing new opportunity for journalism students, their exciting news platform and how they're bringing together seasoned journalists and aspiring ones for a great new venture. Learn more about your ad choices. Visit megaphone.fm/adchoices
Aji-Mallen Sanneh is the owner of Soccer Stars North Dallas along with being the co-founder of Altimate Sports Group - a boutique sports agency focusing aimed to amplify distinct talents and set athletes on a trajectory towards global acclaim. Aji has extensive work experience in global healthcare organizations. She began her career in 2009 as a Program Associate at Management Sciences for Health, where she worked on the Grant Management Solutions project. In 2012, she joined the American Society for Clinical Pathology (ASCP) as an Associate Manager in Global Outreach, later taking on the role of Senior Manager for the Center for Global Health. From 2017 to 2022, Aji worked at The Global Fund, first as a Technical Specialist in HIV Partnerships & Quality, and then as a Specialist in HIV Policy, Partnerships & Strategic Initiatives. Aji has a Master's Degree in Health Policy, Planning and Financing from The London School of Economics and Political Science (LSE) and another Master's Degree in Health Policy, Planning and Financing from the London School of Hygiene and Tropical Medicine. Aji obtained a Bachelor's Degree in Political Science and Government from York University.
Our coffee podcast The Coffee Sprudgecast is back for another rousing episode where hosts Jordan Michelman and Zachary Carlsen take a shortcut… a tiramisu shortcut? Michelman discusses an epic event held with La Marzocco in Florence to promote But First, Coffee that included a whole tiramisu cupping (three cakes that used three different coffees). Carlsen springs a package of Twinkies and claims to be able to make a quick tiramisu out of it. There's some horror, some shock, followed by some shocking surprises. There's so much more. Several coffees are had, all brewed with the Ceado Hoop Brewer. Michelman talks about Monmouth Coffee out of London and a bring-your-own-doughnut-to-a-cafe Dorkage Fee. There's an eccles cake and Lancaster cheese. Coffee ice cream is had. A lot going on here. Have a listen! This episode of the Coffee Sprudgecast is sponsored by Baratza, Pacific Barista Series, Ghirardelli, and DONA. Beverages Discussed On The Podcast DONA Hari River Mint Herbal Tea: Dreaming of springtime, we kick off the episode with DONA's delicious Hari River Mint Herbal Tea which is sundried at the source in Herat, Afghanistan. It's the freshest-tasting dried mint tisane we've had (and we love fresh mint tea). Equator Coffees El Salvador Las Pirineos Gesha Natural & Colombia Finca El Guaca Ahi: Equator Coffees continues to push the envelope with outstanding extra-specialty coffees. We couldn't get enough of both and clearly, others couldn't either—the Aji is out of stock! There are plenty of options on Equator's new arrivals page for your perusal, however, so you can find something. La Marzocco / La Accademia Tanzania Songwa Estates: Visitors at La Marzocco's former factory La Accademia del Caffé can taste the delicious coffees from Songwa Estates of Tanzania roasted on site. La Marzocco, Probat, and Mahlkonig all went in on this project back in 2007 and the coffees shine bright here in 2024. Portland Coffee Roasters Guatemala: Representing one of its lighter roasted coffees, Portland Coffee Roasters' Guatemala comes from their partners Miguelina and Finca El Paternal, a twenty-year relationship that has seen an increase in production innovation with tasty results. Other Mentionables St. John Eccles Cake & Lancashire Cheese Lello Ice Cream Maker by Musto
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
Cette biographie du Cheikh Ahmadou BAMBA (1853-1927), dont le manuscrit arabe est rédigé en 1963 dans un arabe très classique mais clair, comprend 285 pages (Version Rabita AL-KHADÎMIYYAH) et est divisée en 10 chapitres. Son auteur lui a donné le titre de IRWÂ-U- NADÎM MIN' AZHBI HUBB AL- KHADÎM (L'Abreuvement du Commensal dans la Douce Source d'amour du Serviteur) titre assez révélateur du caractère un peu laudatif de son ouvrage qu'il a écrit dans le but de faire connaître le Saint de ce XIVème siècle de l'Hégire (XXème siècle) et de le faire revivre, autrement dit, de contribuer à la diffusion de son œuvre. Commentaire et traduction en wolof : Abdou Khadre BA Majalis __________________________ Irwâ-u Nadîm, di téere bu Sëriñ Muhamadul Amiin Joob Dagana bind ci araab, ci jaar-jaari Seexul Xadiim RLA. Mu tënk ko ci 10i bunt ci 285 xët, ci yaxub Raabita Al-Xadiimiyah. Aji tekki ji ci wolof : Abdul Xaadir BA Majalis --- Send in a voice message: https://podcasters.spotify.com/pod/show/librairie-majalis/message
I'm excited to give you this special New Year's episode of the Wealthy Wellthy Podcast. My dear friend, colleague, successful entrepreneur and coach Ron Macklin, joins me for a deep conversation about setting and fulfilling meaningful goals for the new year. Ron and I met years ago as we journeyed through the Aji Network under the mentorship of Toby Hecht, and since then, Ron and I have collaborated on numerous projects. Our enduring friendship and shared experiences have deeply enriched both our personal and professional lives. During this conversation, we dive deep into Ron's life journey, including his 43-year relationship with his wife Connie, their international escapades, and his philosophy on confronting fears and cultivating ambition. Ron's approach to maintaining a harmonious balance between a successful business and a rich personal life is not only inspiring but also full of practical wisdom, much of which we were taught in Aji. Ron and I explore how to set meaningful goals for the new year, find joy in life's journey, and master the art of experimentation. Interwoven are Ron's profound insights on life, business, and the delicate art of balancing the two. This episode is more than just about goal-setting; it's a guide to enjoying the journey and savoring each moment. Join us as we delve into these enriching discussions and much more!
Joël recaps his time at RubyConf! He shares insights from his talk about different aspects of time in software development, emphasizing the interaction with the audience and the importance of post-talk discussions. Stephanie talks about wrapping up a long-term client project, the benefits of change and variety in consulting, and maintaining a balance between project engagement and avoiding burnout. They also discuss strategies for maintaining work-life balance, such as physical separation and device management, particularly in a remote work environment. Rubyconf (https://rubyconf.org/) Joël's talk slides (https://speakerdeck.com/joelq/which-time-is-it) Flaky test summary slide (https://speakerdeck.com/aridlehoover/the-secret-ingredient-how-to-understand-and-resolve-just-about-any-flaky-test?slide=170) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: Well, as of this recording, I have just gotten back from spending the week in San Diego for RubyConf. STEPHANIE: Yay, so fun. JOËL: It's always so much fun to connect with the community over there, talk to other people from different companies who work in Ruby, to be inspired by the talks. This year, I was speaking, so I gave a talk on time and how it's not a single thing but multiple different quantities. In particular, I distinguish between a moment in time like a point, a duration and amount of time, and then a time of day, which is time unconnected to a particular day, and how those all connect together in the software that we write. STEPHANIE: Awesome. How did it go? How was it received? JOËL: It was very well received. I got a lot of people come up to me afterwards and make a variety of time puns, which those are so easy to make. I had to hold myself back not to put too many in the talk itself. I think I kept it pretty clean. There were definitely a couple of time puns in the description of the talk, though. STEPHANIE: Yeah, absolutely. You have to keep some in there. But I hear you that you don't want it to become too punny [laughs]. What I really love about conferences, and we've talked a little bit about this before, is the, you know, like, engagement and being able to connect with people. And you give a talk, but then that ends up leading to a lot of, like, discussions about it and related topics afterwards in the hallway or sitting together over a meal. JOËL: I like to, in my talks, give little kind of hooks for people who want to have those conversations in the hallway. You know, sometimes it's intimidating to just go up to a speaker and be like, oh, I want to, like, dig into their talk a little bit. But I don't have anything to say other than just, like, "I liked your talk." So, if there's any sort of side trails I had to cut for the talk, I might give a shout-out to it and say, "Hey, if you want to learn more about this aspect, come talk to me afterwards." So, one thing that I put in this particular talk was like, "Hey, we're looking at these different graphical ways to think about time. These are similar to but not the same as thinking of time as a one-dimensional vector and applying vector math to it, which is a whole other side topic. If you want to nerd out about that, come find me in the hallway afterwards, and I'd love to go deeper on it." And yeah, some people did. STEPHANIE: That's really smart. I like that a lot. You're inviting more conversation about it, which I know, like, you also really enjoy just, like, taking it further or, like, caring about other people's experiences or their thoughts about vector math [laughs]. JOËL: I think it serves two purposes, right? It allows people to connect with me as a speaker. And it also allows me to feel better about pruning certain parts of my talk and saying, look, this didn't make sense to keep in the talk, but it's cool material. I'd love to have a continuing conversation about this. So, here's a path we could have taken. I'm choosing not to, as a speaker, but if you want to take that branch with me, let's have that afterwards in the hallway. STEPHANIE: Yeah. Or even as, like, new content for yourself or for someone else to take with them if they want to explore that further because, you know, there's always something more to explore [chuckles]. JOËL: I've absolutely done that with past talks. I've taken a thing I had to prune and turned it into a blog post. A recent example of that was when I gave a talk at RailsConf Portland, which I guess is not so recent. I was talking about ways to deal with a test suite that's making too many database requests. And talking about how sometimes misusing let in your RSpec tests can lead to more database requests than you expect. And I had a whole section about how to better understand what database requests will actually be made by a series of let expressions and dealing with the eager versus lazy and all of that. I had to cut it. But I was then able to make a blog post about it and then talk about this really cool technique involving dependency graphs. And that was really fun. So, that was a thing where I was able to say, look, here's some content that didn't make it into the talk because I needed to focus on other things. But as its own little, like, side piece of content, it absolutely works, and here's a blog post. STEPHANIE: Yeah. And then I think it turned into a Bike Shed episode, too [laughs]. JOËL: I think it did, yes. I think, in many ways, creativity begets creativity. It's hard to get started writing or producing content or whatever, but once you do, every idea you have kind of spawns new ideas. And then, pretty soon, you have a backlog that you can't go through. STEPHANIE: That's awesome. Any other highlights from the conference you want to shout out? JOËL: I'd love to give a shout-out to a couple of talks that I went to, Aji Slater's talk on the Enigma machine as a German code machine from World War II and how we can sort of implement our own in Ruby and an exploration of object-oriented programming was fantastic. Aji is just a masterful storyteller. So, that was really great. And then Alan Ridlehoover's talk on dealing with flaky tests that one, I think, was particularly useful because I think it's one of the talks that is going to be immediately relevant on Monday morning for, like, every developer that was in that room and is going back to their regular day job. And they can immediately use all of those principles that Alan talked about to deal with the flaky tests in their test suite. And there's, in particular, at the end of his presentation, Alan has this summary slide. He kind of broke down flakiness across three different categories and then talked about different strategies for identifying and then fixing tests that were flaky because of those reasons. And he has this table where he sort of summarizes basically the entire talk. And I feel like that's the kind of thing that I'm going to save as a cheat sheet. And that can be, like, I'm going to link to this and share it all over because it's really useful. Alan has already put his slides up online. It's all linked to that particular slide in the show notes because I think that all of you would benefit from seeing that. The talks themselves are recorded, but they're not going to be out for a couple of weeks. I'm sure when they do, we're going to go through and watch some and probably comment on some of the talks as well. So, Stephanie, what is new in your world? STEPHANIE: Yeah. So, I'm celebrating wrapping up a client project after a nine-month engagement. JOËL: Whoa, that's a pretty long project. STEPHANIE: Yeah, that's definitely on the longer side for thoughtbot. And I'm, I don't know, just, like, feeling really excited for a change, feeling really, you know, proud of kind of, like, all of the work that we had done. You know, we had been working with this client for a long time and had been, you know, continuing to deliver value to them to want to keep working with us for that long. But I'm, yeah, just looking forward to a refresh. And I think that's one of my favorite things about consulting is that, you know, you can inject something new into your work life at a kind of regular cadence. And, at least for me, that's really important in reducing or, like, preventing the burnout. So, this time around, I kind of started to notice, and other people, too, like my manager, that I was maybe losing a bit of steam on this client project because I had been working on it for so long. And part of, you know, what success at thoughtbot means is that, like, we as employees are also feeling fulfilled, right? And, you know, what are the different ways that we can try to make sure that that remains the case? And kind of rotating folks on different projects and kind of making sure that things do feel fresh and exciting is really important. And so, I feel very grateful that other people were able to point that out for me, too, when I wasn't even fully realizing it. You know, I had people checking in on me and being like, "Hey, like, you've been on this for a while now. Kind of what I've been hearing is that, like, maybe you do need something new." I'm just excited to get that change. JOËL: How do you find the balance between sort of feeling fulfilled and maybe, you know, finding that point where maybe you're feeling you're running out of steam–versus, you know, some projects are really complex, take a while to ramp up; you want to feel productive; you want to feel like you have contributed in a significant way to a project? How do you navigate that balance? STEPHANIE: Yeah. So, the flip side is, like, I also don't think I would enjoy having to be changing projects all the time like every couple of months. That maybe is a little too much for me because I do like to...on our team, Boost, we embed on our team. We get to know our teammates. We are, like, building relationships with them, and supporting them, and teaching them. And all of that is really also fulfilling for me, but you can't really do that as much if you're on more shorter-term engagements. And then all of that, like, becomes worthwhile once you're kind of in that, like, maybe four or five six month period where you're like, you've finally gotten your groove. And you're like, I'm contributing. I know how this team works. I can start to see patterns or, like, maybe opportunities or gaps. And that is all really cool, and I think also another part of what I really like about being on Boost. But yeah, I think what I...that losing steam feeling, I started to identify, like, I didn't have as much energy or excitement to push forward change. When you kind of get a little bit too comfortable or start to get that feeling of, well, these things are the way they are [laughs], -- JOËL: Right. Right. STEPHANIE: I've now identified that that is kind of, like, a signal, right? JOËL: Maybe time for a new project. STEPHANIE: Right. Like starting to feel a little bit less motivated or, like, less excited to push myself and push the team a little bit in areas that it needs to be pushed. And so, that might be a good time for someone else at thoughtbot to, like, rotate in or maybe kind of close the chapter on what we've been able to do for a client. JOËL: It's hard to be at 100% all the time and sort of always have that motivation to push things to the max, and yeah, variety definitely helps with that. How do you feel about finding signals that maybe you need a break, maybe not from the project but just in general? The idea of taking PTO or having kind of a rest day. STEPHANIE: Oh yeah. I, this year, have tried out taking time off but not going anywhere just, like, being at home but being on vacation. And that was really great because then it was kind of, like, less about, like, oh, I want to take this trip in this time of year to this place and more like, oh, I need some rest or, like, I just need a little break. And that can be at home, right? Maybe during the day, I'm able to do stuff that I keep putting off or trying out new things that I just can't seem to find the time to do [chuckles] during my normal work schedule. So, that has been fun. JOËL: I think, yeah, sometimes, for me, I will sort of hit that moment where I feel like I don't have the ability to give 100%. And sometimes that can be a signal to be like, hey, have you taken any time off recently? Maybe you should schedule something. Because being able to refresh, even short-term, can sort of give an extra boost of energy in a way where...maybe it's not time for a rotation yet, but just taking a little bit of a break in there can sort of, I guess, extend the time where I feel like I'm contributing at the level that I want to be. STEPHANIE: Yeah. And I actually want to point out that a lot of that can also be, like, investing in your life outside of work, too, so that you can come to work with a different approach. I've mentioned the month that I spent in the Hudson Valley in New York and, like, when I was there, I felt, like, so different. I was, you know, just, like, so much more excited about all the, like, novel things that I was experiencing that I could show up to work and be like, oh yeah, like, I'm feeling good today. So, I have all this, you know, energy to bring to the tasks that I have at work. And yeah, so even though it wasn't necessarily time off, it was investing in other things in my life that then brought that refresh at work, even though nothing at work really changed [laughs]. JOËL: I think there's something to be said for the sort of energy boost you get from novelty and change, and some of that you get it from maybe rotating to a different project. But like you were saying, you can change your environment, and that can happen as well. And, you know, sometimes it's going halfway across the country to live in a place for a month. I sometimes do that in a smaller way by saying, oh, I'm going to work this morning from a coffee shop or something like that. And just say, look, by changing the environment, I can maybe get some focus or some energy that I wouldn't have if I were just doing same old, same old. STEPHANIE: Yeah, that's a good point. So, one particularly surprising refresh that I experienced in offboarding from my client work is coming back to my thoughtbot, like, internal company laptop, which had been sitting gathering dust [laughs] a little bit because I had a client-issued laptop that I was working in most of the time. And yeah, I didn't realize how different it would feel. I had, you know, gotten everything set up on my, you know, my thoughtbot computer just the way that I liked it, stuff that I'd never kind of bothered to set up on my other client-issued laptop. And then I came back to it, and then it ended up being a little bit surprising. I was like, oh, the icons are smaller on this [laughs] computer than the other computer. But it definitely did feel like returning to home, I think, instead of, like, being a guest in someone else's house that you haven't quite, like, put all your clothes in the closet or in the drawers. You're still maybe, like, living out of a suitcase a little bit [laughs]. So yeah, I was kind of very excited to be in my own space on my computer again. JOËL: I love the metaphor of coming home, and yeah, being in your own space, sleeping in your own bed. There's definitely some of that that I feel, I think, when I come back to my thoughtbot laptop as well. Do you feel like you get a different sense of connection with the rest of our thoughtbot colleagues when you're working on the thoughtbot-issued laptop versus a client-issued one? STEPHANIE: Yeah. Even though on my client-issued computer I had the thoughtbot Slack, like, open on there so I could be checking in, I wasn't necessarily in, like, other thoughtbot digital spaces as much, right? So, our, like, project management tools and our, like, internal company web app, those were things that I was on less of naturally because, like, the majority of my work was client work, and I was all in their digital spaces. But coming back and checking in on, like, all the GitHub discussions that have been happening while I haven't had enough time to catch up on them, just realizing that things were happening [laughs] even when I was doing something else, that is both cool and also like, oh wow, like, kind of sad that I [chuckles] missed out on some of this as it was going on. JOËL: That's pretty similar to my experience. For me, it almost feels a little bit like the difference between back when we used to be in person because thoughtbot is now fully remote. I would go, usually, depending on the client, maybe a couple of days a week working from their offices if they had an office. Versus some clients, they would come to our office, and we would work all week out of the thoughtbot offices, particularly if it was like a startup founder or something, and they might not already have office space. And that difference and feeling the connection that I would have from the rest of the thoughtbot team if I were, let's say, four days a week out of a client office versus two or four days a week out of the thoughtbot office feels kind of similar to what it's like working on a client-issued laptop versus on a thoughtbot-issued one. STEPHANIE: Another thing that I guess I forgot about or, like, wasn't expecting to do was all the cleanup, just the updating of things on my laptop as I kind of had it been sitting. And it reminded me to, I guess, extend that, like, coming home metaphor a little bit more. In the game Animal Crossing, if you haven't played the game in a while because it tracks, like, real-time, so it knows if you haven't, you know, played the game in a few months, when you wake up in your home, there's a bunch of cockroaches running around [laughs], and you have to go and chase and, like, squash them to clean it up. JOËL: Oh no. STEPHANIE: And it kind of felt like that opening my computer. I was like, oh, like, my, like, you know, OS is out of date. My browsers are out of date. I decided to get an internal company project running in my local development again, and I had to update so many things, you know, like, install the new Ruby version that the app had, you know, been upgraded to and upgrade, like, OpenSSL and all of that stuff on my machine to, yeah, get the app running again. And like I mentioned earlier, just the idea of like, oh yeah, this has evolved and changed, like, without me [laughs] was just, you know, interesting to see. And catching myself up to speed on that was not trivial work. So yeah, like, all that maintenance stuff still got to do it. It's, like, the digital cleanup, right? JOËL: Exactly. So, you mentioned that on the client machine, you still had the thoughtbot Slack. So, you were able to keep up at least some messages there on one device. I'm curious about the experience, maybe going the other way. How much does thoughtbot stuff bleed into your personal devices, if at all? STEPHANIE: Barely. I am very strict about that, I think. I used to have Slack on my phone, I don't know, just, like, in an earlier time in my career. But now I have it a rule to keep it off. I think the only thing that I have is my calendar, so no email either. Like, that is something that I, like, don't like to check on my personal time. Yeah, so it really just is calendar just in case I'm, like, out in the morning and need to be, like, oh, when is my first meeting? But [laughs] I will say that the one kind of silly thing is that I also refuse to sign into my Google account for work. So, I just have the calendar, like, added to my personal calendar but all the events are private. So, I can't actually see what the events are [laughs]. I just know that I have something going on at, like, 10:00 a.m. So, I got to make sure I'm back home by then [laughs], which is not so ideal. But at the risk of being signed in and having other things bleed into my personal devices, I'm just living with that for now [laughs]. JOËL: What I'm hearing is that I could put some mystery events on your calendar, and you would have a fun surprise in the morning because you wouldn't know what it is. STEPHANIE: Yeah, that is true [laughs]. If you put, like, a meeting at, like, 8:00 a.m., [laughs] then I'm like, oh no, what's this? And then I arrive, and it's just, like [laughs], a fun prank meeting. So, you know, you were talking about how you were at the conference this week. And I'm wondering, how connected were you to work life? JOËL: Uh, not very. I tried to be very present in the moment at the conference. So, I'm, you know, connected to all the other thoughtboters who were there and connecting with the attendees. I do have Slack on my phone, so if I do need to check it for something. There was a little bit of communication that was going on for different things regarding the conference, so I did check in for that. But otherwise, I tried to really stay focused on the in-person things that are happening. I'm not doing any client work during those days that I'm at RubyConf, and so I don't need to deal with anything there. I had my thoughtbot laptop with me because that's what I used to give my presentation. But once the presentation was done, I closed that laptop and didn't open it again, and, honestly, that felt kind of good. STEPHANIE: Yeah, that is really nice. I'm the same way, where I try to be pretty connected at conferences, and, like, I will actually redownload Slack sometimes just for, like, coordinating purposes with other folks who are there. But I think I make it pretty clear that I'm, like, away. You know, like, I'm not actually...like, even though I'm on work time, I'm not doing any other work besides just being present there. JOËL: So, you mentioned the idea of work time. Do you have, like, a pretty strict boundary between personal time and work time and, like, try not to allow either to bleed into each other? STEPHANIE: Yeah. I can't remember if I've mentioned this on the show. I think I have, but I'm going to again because one of my favorite things that I picked up from The Bike Shed back when Chris Toomey and Steph Viccari were hosting the show is Chris had, like, a little ritual that he would do every day to signal that he was done with work. He would close his laptop and say, "Schedule shutdown complete," I think. And I've started adopting it because then it helps me be like, I'm not going to reopen my laptop after this because I have said the words. And even if I think of something that I maybe need to add to my to-do list, I will, instead of opening my computer and adding to my, like, whatever digital to-do list, I will, like, write it down on a piece of paper instead for the sake of, you know, not risking getting sucked back into, you know, whatever might be going on after the time that I've, like, decided that I need to be done. JOËL: So, you have a very strict divisioning between work time and personal time. STEPHANIE: Yeah, I would say so. I think it's important for me because even when I take time off, you know, sometimes folks might work a half day or something, right? I really struggle with having even a half day feel like, once I'm done with work, having that feel like okay, like, now I'm back in my personal time. I'd much prefer not working the entire day at all because that is kind of the only way that I can feel like I've totally reclaimed that time. Otherwise, it's like, once I start thinking about work stuff, it's like I need a mental boundary, right? Because if I'm thinking about a work problem, or, like, an interaction or, like, just anything, it's frustrating because it doesn't feel like time in my own brain [laughs] is my own. What do work and personal time boundaries look like for you? JOËL: I think it's evolved over time. Device usage is definitely a little bit more blurry for me. One thing that I have started doing since we've gone fully remote as the pandemic has been winding down and, you know, you can do things, but we're still working from home, is that more days than not, I work from home during the day, and then I leave my home during the evening. I do a variety of social activities. And because I like to be sort of present in the moment, that means that by being physically gone, I have totally disconnected because I'm not checking emails or anything like that. Even though I do have thoughtbot email on my phone, Gmail allows me to like log into my personal account and my thoughtbot account. I have to, like, switch between the two accounts, and so, that's, like, more work than I would want. I don't have any notifications come in for the thoughtbot account. So, unless I'm, like, really wanting to see if a particular email I'm waiting for has come in, I don't even look at it, ever. It's mostly just there in case I need to see something. And then, by being focused in the moment doing social things with other people, I don't find too much of a temptation to, like, let work life bleed into personal life. So, there's a bit of a physical disconnect that ends up happening by moving out of the space I work in into leaving my home. STEPHANIE: Yeah. And I'm sure it's different for everyone. As you were saying that, I was reminded of a funny meme that I saw a long time ago. I don't think I could find it if I tried to search for it. But basically, it's this guy who is, you know, sitting on one side of the couch, clearly working. And he's kind of hunched over and, like, typing and looking very serious. And then he, like, closes his laptop, moves over, like, just slides to the other side of the couch, opens his laptop. And then you see him, like, lay back, like, legs up on the coffee table. And it's, like, work computer, personal computer, but it's the same computer [laughs]. It's just the, like, how you've decided like, oh, it's time for, you know, legs up, Netflix watching [laughs]. JOËL: Yeah. Yeah. I'm curious: do you use your thoughtbot computer for any personal things? Or is it just you shut that down; you do the closing ritual, and then you do things on a separate device? STEPHANIE: Yeah, I do things on a separate device. I think the only thing there might be some overlap for are, like, career-related extracurriculars or just, like, development stuff that I'm interested in doing, like, separate from what I am paid to do. But that, you know, kind of overlaps a little bit because of, like, the tools and the stuff I have installed on my computer. And, you know, with our investment time, too, that ends up having a bit of a crossover. JOËL: I think I'm similar in that I'll tend to do development things on my thoughtbot machine, even though they're not necessarily thoughtbot-related, although they could be things that might slot into something like investment time. STEPHANIE: Yeah, yeah. And it's because you have all your stuff set up for it. Like, you're not [laughs] trying to install the latest Ruby version on two different machines, probably [laughs]. JOËL: Yeah. Also, my personal device is a Windows machine. And I've not wanted to bother learning how to set that up or use the Windows Subsystem for Linux or any of those tools, which, you know, may be good professional learning activities. But that's not where I've decided to invest my time. STEPHANIE: That makes sense. I had an interesting conversation with someone else today, actually, about devices because I had mentioned that, you know, sometimes I still need to incorporate my personal devices into work stuff, especially, like, two-factor authentication. And specifically on my last client project...I have a very old iPhone [laughs]. I need to start out by saying it's an iPhone 8 that I've had for, like, six or seven years. And so, it's old. Like, one time I went to the Apple store, and I was like, "Oh, I'm looking for a screen protector for this." And they're like, "Oh, it's an iPhone 8. Yikes." [laughs] This was, you know, like, not too long ago [laughs]. And the multi-factor authentication policy for my client was that, you know, we had to use this specific app. And it also had, like, security checks. Like, there's a security policy that it needed to be updated to the latest iOS. So, even if I personally didn't want to update my iOS [laughs], I felt compelled to because, otherwise, I would be locked out of the things that I needed to do at work [laughs]. JOËL: Yeah, that can be a challenge sometimes when you're adding work things to personal devices, maybe not because it's convenient and you want to, but because you don't have a choice for things like two-factor auth. STEPHANIE: Yeah, yeah. And then the person I was talking to actually suggested something I hadn't even thought about, which is like, "Oh, you know, if you really can't make it work, then, like, consider having that company issue another device for you to do the things that they're, like, requiring of you." And I hadn't even thought of that, so... And I'm not quite at the point where I'm like, everything has to be, like, completely separate [laughs], including two-factor auth. But, I don't know, something to consider, like, maybe that might be a place I get to if I'm feeling like I really want to keep those boundaries strict. JOËL: And I think it's interesting because, you know, when you think of the kind of work that we do, it's like, oh, we work with computers, but there are so many subfields within it. And device management and, just maybe, corporate IT, in general, is a whole subfield that is separate and almost a little bit alien. Two, I feel like me, as a software developer, I'm just aware of a little bit...like, I've read a couple of articles around...and this was, you know, years ago when the trend was starting called Bring Your Own Device. So, people who want to say, "Hey, I want to use my phone. I want to have my work email on my phone." But then does that mean that potentially you're leaking company memos and things? So, how do you secure that kind of thing? And everything that IT had to think through in order to allow that, the pros and cons. So, I think we're just kind of, as users of that system, touching the surface of it. But there's a lot of thought and discussion that, as an industry, the kind of corporate IT folks have gone through to struggle with how to balance a lot of those things. STEPHANIE: Yeah, yeah. I bet there's a lot of complexity or nuance there. I mean, we're just talking about, like, ways that we do or don't mix work and personal life. And for that kind of work, you know, that's, like, the job is to think really thoroughly about how people use their devices and what should and shouldn't be permissible. The last thing that I wanted to kind of ask about in terms of device management or, like, work and personal intermixing is the idea of being on call and your device being a way for work to reach you and that being a requirement, right? I feel very lucky to obviously not really be in that position. As consultants, like, we're not usually so embedded into a team that we're then brought into, like, an on-call rotation, and I think that's good for me. Like, I don't think that that is something I'd be interested in doing anytime soon. Do you have any experience with that? JOËL: I have not been on a project where I've had to be on call, and I think that's generally true for most of us at thoughtbot who are doing software development. I know those who are doing more kind of platformy SRE-type things are on call. And, in fact, we have specifically hired people in different regions around the world so that we can provide 24-hour coverage for that kind of thing. STEPHANIE: Yeah. And I imagine kind of like what we're talking about with work device management looks even different for that kind of role, where maybe you do need a lot more access to things, like, wherever you might be. JOËL: And maybe the answer there is you get issued a work-specific device and a work phone or something like that, or an old-school work pager. STEPHANIE: [laughs] JOËL: PagerDuty is not just a metaphoric thing. Back in the day, they used actual pagers. STEPHANIE: Yeah, that would be very funny. JOËL: So yeah, I can't speak to it from personal experience, but I could imagine that maybe some of the dynamics there might be a little bit different. And, you know, for some people, maybe it's fine to just have an app on your phone that pings you when something happens, and you have to be on call. And you're able to be present while waiting, like, in case you get pinged, but also let it go while you're on call. I can imagine that's, like, a really weird kind of, like, shadow, like, working, not working experience that I can't really speak to because I have not been in that position. STEPHANIE: Yeah. As you were saying that, I also had the thought that, like, our ability to step away from work and our devices is also very much dependent on, like, a company culture and those types of factors, right? Where, you know, it is okay for me to not be able to look at that stuff and just come back to it Monday morning, and I am very grateful [laughs] for that. Because I recognize that, like, not everyone is in that position where there might be a lot more pressure or urgency to be on top of that. But right now, for this time in my life, like, that's kind of how I like to work. JOËL: I think it kind of sits at the intersection of a few different things, right? There's sort of where you are personally. It might be a combination, like, personality and maybe, like, mental health, things like that, how you respond to how sharp or blurry those lines between work and personal life can be. Like you said, it's also an element of company culture. If there's a company culture that's really pushing to get into your personal life, maybe you need firmer boundaries. And then, finally, what we spent most of this episode talking about: technical solutions, whether that's, like, physically separating everything such that there are two devices. And you close down your laptop, and you're done for the day. And whether or not you allow any apps on your personal phone to carry with you after you leave for the day. So, I think at the intersection of those three is sort of how you're going to experience that, and every person is going to be a little bit different. Because those three...I guess I'm thinking of a Venn diagram. Those three circles are going to be different for everyone. STEPHANIE: Yeah, that makes complete sense. JOËL: On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at: referrals@thoughtbot.com with any questions.
A continued message by Aji
For this week's episode, Aji & Mina read Action View Overview and discuss templating systems, the difference between Action and Active, and internationalization as a bonus view template feature.Reading for this episode: Action View Overview https://guides.rubyonrails.org/action_view_overview.htmlEileen's Railsconf 2023 Keynote: https://youtu.be/TgNb2_LSMMo?si=ymjnJ7DOvZQDp6vbTailwind and the Femininity of CSS: https://thoughtbot.com/blog/tailwind-and-the-femininity-of-cssHotwiring My React Brain at RailsConf 2023: https://www.youtube.com/watch?v=V37Q3xy3pUoLet's Standardize Rails at Railsconf 2023: https://youtu.be/cj9NO1xI4b4?si=NRVm-UbXkxvGmzUBReading for episode 13: Layouts and Rendering in Rails https://guides.rubyonrails.org/layouts_and_rendering.html
For this week's episode, Aji and Guest Host Sally Hall discussed Active model, form objects and presenters, APIs as database, and Rails inflectors and translation.Reading for this episode: Active Model Basics
Aji & guest host Mercedes Bernard talk ORMs & SQL, left outer joins & includes, and strict & eager loading.Reading for this episode: Active Record Query InterfaceThe Bike Shed episode 358: The Class MethodReading for next episode: Active Model BasicsFind Mercedes online at mercedesbernard.com, on mastodon: mercedescodes@mastodon.world, or LinkedIn
Aji welcomes guest host and fellow thoughtbotter Dimiter Petrov. Their conversation covers association scope, the thoughtful layout of this section of the guides, polymorphic associations, and association extensions.Reading for this episode: Active Record AssociationsHelvetic Ruby: Ruby conference in Bern, Switzerland, November 24, 2023Reading for next episode: Active Record Query Interface
For this week's episode, Aji welcomes our very first Guest Host, Sasha Grodzins! Aji & Sasha read about Active Record Callbacks and discuss pitfalls of callbacks, how they are similar to validations, and comments and commit messages as documentation.Reading for this episode: Active Record Callbacks5 Rails Callbacks Best Practices Used at GustoRuby Science's chapter on callbacksActive Record callbacks source codeAji at RailsConf 2019: Commit Messages to the rescue!Reading for episode 9: Active Record Associations
A message from Aji
For this week's episode, Aji & Mina read "Active Record Validations" and discuss their most-used validation helpers, how they interpreted the validates_associated section of the Guides, and when not to over-validate.Reading for this episode: "Active Record Validations"Time for a Boolean gemWhat's in a name (validation)?Creating More Inclusive and Culturally Sensitive FormsReading for episode 8: Active Record Callbacks
For this week's episode, Aji & Mina discuss chapters 5 through 9 of "Active Record Migrations". They debate migration file management, and touch on the relationship between end users and application data, and learning complex concepts within Rails' convention over configuration framework.Reading for this episode: "Active Record Migrations", chapters 5-9thoughtbot's AWS Platform Guide (Flightdeck)Reading for episode 7: "Active Record Validations"
She'd never made guacamole before. While mashing the avocados, Dyana saw a bottle of Aji condiment, a speciality in Colombia and South America. The rest, they say is history. Talk to Nicholas here: https://www.linkedin.com/in/nicholas-gonzalez-biagi-7b3193101/ Shop for Dyana's Aji Sauces here: https://www.ajigourmetproducts.com/
For this week's episode, Aji & Mina read chapters 1 through 4 in “Active Record Migrations” and discuss command line generator options, database-level comments, and reverting migrations.Reading for this episode: "Active Record Migrations", chapters 1-4Reading for episode 6: "Active Record Migrations", chapters 5-9
Aji tells us a message encouraging us to be more thankful. Pray always and be thankful in Christ!
Joël gives a recap after attending RailsConf 2023 in Atlanta, Georgia (and yes, there was karaoke!
Aron Aji discusses the life and work of Turkish author Ferit Edgü. Aji's translations of Edgu's excellent, austere novellas “The Wounded Age” and “Eastern Tales” were recently published in a new single volume by New York Review Books. Become a member to support Turkey Book Talk. Members get a 35% discount on all Turkey/Ottoman History books published by IB Tauris/Bloomsbury, transcripts of every interview, transcripts of the whole archive, and over 200 reviews covering Turkish and international fiction, history and politics.
Aji walks us through the relationship between grace and peace.
Aji gives another great message from Colossians
Aji amarillo is a type of chili pepper that is native to Peru and is commonly used in Peruvian cuisine. It has a bright orange color and a slightly fruity, spicy flavor that adds depth and heat to dishes. Aji amarillo is a staple in many Peruvian restaurants and is often used to create flavorful sauces, marinades, and condiments. Peruvian cuisine has gained popularity in recent years, and many restaurants in the United States now feature dishes that incorporate aji amarillo. Some popular Peruvian dishes that feature aji amarillo include ceviche, lomo saltado, and aji de gallina. These dishes often include aji amarillo peppers, either fresh or in the form of a sauce, to add flavor and heat. In addition to traditional Peruvian restaurants, aji amarillo is also finding its way into non-Peruvian restaurants in the United States. Some chefs are experimenting with using aji amarillo in new and creative ways, incorporating it into dishes that may not traditionally feature the pepper. For example, aji amarillo may be used to add flavor and heat to grilled meats, sauces for pasta or pizza, or even in desserts such as ice cream or sorbet. I'd like to share a potential educational resource, "Conversations Behind the Kitchen Door", my new book that features dialogues with accomplished culinary leaders from various backgrounds and cultures. It delves into the future of culinary creativity and the hospitality industry, drawing from insights of a restaurant-industry-focused podcast, ‘flavors unknown”. It includes perspectives from renowned chefs and local professionals, making it a valuable resource for those interested in building a career in the culinary industry. Get the book here! The taste of the Aji Amarillo Aji Amarillo has a distinct, fruity and slightly sweet flavor, with a moderate to high level of heat. The heat level can vary depending on the specific pepper and where it is grown. The heat typically builds up slowly in the mouth, and the flavor can linger for a while after eating. Some people describe the flavor as having notes of apricot, peach, or tropical fruit. Aji amarillo is often used to add a unique and complex flavor to dishes, rather than just heat. It's versatile and can be used in many ways in your cooking. Three unexpected recipes that use aji amarillo: Savory dish: Aji Amarillo Mashed Potatoes - To make this dish, you will need to roast a few aji amarillo peppers and blend them with mashed potatoes, butter, and milk. This will add a spicy, flavorful twist to your traditional mashed potatoes. Dessert or ice cream: Aji Amarillo Sorbet - To make this sorbet, you will need to blend aji amarillo peppers with sugar, water, and lime juice. The result will be a spicy, refreshing sorbet that is perfect for a hot summer day. Cocktail: Aji Amarillo Margarita - To make this cocktail, you will need to blend aji amarillo peppers with tequila, lime juice, and orange liqueur. This will create a spicy, flavorful margarita that is sure to impress your friends. Three examples of menu dishes using aji amarillo outside of Peruvian restaurants Spicy Aji Amarillo Chicken Wings - These chicken wings are coated in a spicy aji amarillo sauce, which adds a bold, flavorful kick to the wings. They can be served as an appetizer or as a main course, and are sure to be a hit with spicy food fans. Aji Amarillo Shrimp Pasta - This pasta dish features shrimp tossed in a creamy aji amarillo sauce, which adds a spicy, fruity flavor to the dish. It can be served with your choice of pasta and garnished with fresh herbs and Parmesan cheese. Grilled Aji Amarillo Steak - This steak is marinated in a spicy aji amarillo sauce before being grilled to perfection. The aji amarillo adds a bold, flavorful kick to the steak, making it a unique and delicious main course. 10 examples of dishes with Aji Amarillo Chicken: Aji amarillo can be used to create spicy, flavorful marinades or sauces for grilled or roasted chicken.
Joël's been traveling. Stephanie's working on professional development. She's also keeping up a little bit more with Ruby news and community news in general and saw that Ruby 3.2 introduced a new class called data to its core library for the use case of creating simple value objects. This episode is brought to you by Airbrake (https://airbrake.io/?utm_campaign=Q3_2022%3A%20Bike%20Shed%20Podcast%20Ad&utm_source=Bike%20Shed&utm_medium=website). Visit Frictionless error monitoring and performance insight for your app stack. Maggie Appleton's Tools for Thought (https://maggieappleton.com/tools-for-thought) Episode on note-taking with Amanda Beiner (https://www.bikeshed.fm/357) Obsidian (https://obsidian.md/) Zettelkasten (https://zettelkasten.de/posts/overview/) Evergreen notes (https://notes.andymatuschak.org/Evergreen_notes) New Data class (https://ruby-doc.org/3.2.0/Data.html) Joël's article on value objects (https://thoughtbot.com/blog/value-object-semantics-in-ruby) Episode on specialized vocabulary (https://www.bikeshed.fm/356) Primitive Obsession (https://wiki.c2.com/?PrimitiveObsession) Transcript: AD: thoughtbot is thrilled to announce our own incubator launching this year. If you are a non-technical founding team with a business idea that involves a web or mobile app, we encourage you to apply for our eight-week program. We'll help you move forward with confidence in your team, your product vision, and a roadmap for getting you there. Learn more and apply at tbot.io/incubator. STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a little bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: I've been traveling for the past few weeks in Europe. I just recently got back to the U.S. and have just gotten used to drinking American-style drip coffee again after having espresso every day for a few weeks. And it's been an adjustment. STEPHANIE: I bet. I think that it's such a downgrade compared to European espresso. I remember when I was in Italy, I also would really enjoy espresso every day at a local cafe and just be like sitting outside drinking it. And it was very delightful. JOËL: They're very different experiences. I have to say I do enjoy just holding a hot mug and sort of sipping on it for a long time. It's also a lot weaker. You wouldn't want to do a full hot mug of espresso. That would just be way too intense. But yeah, I think both experiences are enjoyable. They're just different. STEPHANIE: Yeah. So, that first day with your measly drip coffee and your jet lag, how are you doing on your first day back at work? JOËL: I did pretty good. I think part of the fun of coming back to the U.S. from Europe is that the jet lag makes me a very productive morning person for a week. Normally, I'm a little bit more of an evening person. So I get to get a bit of an alter ego for a week, and that helps me to transition back into work. STEPHANIE: Nice. JOËL: So you've also been on break and have started work again. How are you feeling productivity-wise, kicking off the New Year? STEPHANIE: I'm actually unbooked this week and the last week too. So I'm not working on client projects, but I am having a lot of time to work on just professional development. And usually, during this downtime, I also like to reassess just how I'm working, and lately, what that has meant for me is changing my note-taking process. And I'm really excited to share this with you because I know that you have talked about this on the show before, I think in a previous episode with a guest, Amanda Beiner. And I listened to that episode, and I was really inspired because I was feeling like I didn't have a note-taking system that worked super well for me. But you all talked about some tools you used and some, I guess, philosophies around note-taking that like I said, I was really inspired by. And so I hopped on board the Obsidian train. And I'm really excited to share with you my experience with it. So I really like it because I previously was taking notes in my editor under the impression that, oh, like, everything is in one place. It'll be like a seamless transition from code to note-taking. And I was already writing in Markdown. But I actually didn't like it that much because I found it kind of distracting to have code things kind of around. And if I was navigating files or something, something work or code-related might come up, and that ended up being a bit distracting for me. But I know that that works really well for some people; a coworker of ours, Aji, I know that he takes his notes in Vim and has a really fancy setup for that. And so I thought maybe that's what I wanted, but it turns out that what I wanted was actually more of a boundary between code and notes. And so, I was assessing different note-taking and knowledge management software. And I have been really enjoying Obsidian because it also has quite a bit of community support. So I've installed a few plugins for just quality-of-life features like snippets which I had in my editor, and now I get to have in Obsidian. I also installed things like Natural Language Dates. So for my running to-do list, I can just do a shortcut for today, and it'll autofill today's date, which, I don't know, because for me, [laughs] that is just a little bit less mental work that I have to do to remember the date. And yeah, I've been really liking it. I haven't even fully explored backlinking, and that connectivity aspect, which I know is a core feature, but it's been working well for me so far. JOËL: That's really exciting. I love notes and note-taking and the ways that we can use those to make our lives better as developers and as human beings. Do you have a particular system or way you've approached that? Because I know for me, I probably looked at Obsidian for six months before I kind of had the courage to download it because I didn't want to go into it and not have a way to organize things. I was like; I don't want to just throw random notes in here. I want to have a system. That might just be me. But did you just kind of jump into it and see, like, oh, a system will emerge? Did you have a particular philosophy going in? How are you approaching taking notes there? STEPHANIE: That's definitely a you thing because I've definitely had the opposite experience [laughs] where I'm just like, oh, I've downloaded this thing. I'm going to start typing notes and see what happens. I have never really had a good organizational system, which I think is fine for me. I was really leaning on pen and paper notes for a while, and I still have a certain use case for them. Because I find that when I'm in meetings or one-on-ones and taking notes, I don't actually like to have my hands on the keyboard because of distractions. Like I mentioned earlier, it's really easy for me to, like, oh, accidentally Command-Tab and open Slack and be like, oh, someone posted something new in Slack; let me go read this. And I'm not giving the meeting or the person I'm talking to my full attention, and I really didn't like that. So I still do pen and paper for things where I want to make sure that I'm not getting distracted. And then, I will transfer any gems from those notes to Obsidian if I find that they are worth putting in a place where I do have a little bit more discoverability and eventually maybe kind of adding on to my process of using those backlinks and connecting thoughts like that. So, so far, it's truly just a list of separate little pages of notes, and yeah, we'll see how it goes. I'm curious what your system for organizing is or if you have kind of figured out something that works well for you. JOËL: So my approach focuses very heavily on the backlinks. It's loosely inspired by two similar systems of organization called Zettelkasten and evergreen notes. The idea is that you create notes that are ideas. Typically, the title is like a thesis statement, and you keep them very short, focused on a single thing. And if you have a more complex idea, it probably breaks down into two or three, and then you link them to each other as makes sense. So you create a web of these atomic ideas that are highly interconnected with each other. And then later on, because I use this a lot for either creating content in the future or to help refine my thinking on various software topics, so later on, I can go through and maybe connect three or four things I didn't realize connected together. Or if I'm writing an article or a talk, maybe find three or four of these ideas that I generated at very different moments, but now they're connected. And I can make an article or a talk out of them. So that's sort of the purpose that I use them for and how I've organized things for myself. STEPHANIE: I think that's a really interesting topic because while I was assessing different software for note-taking and, like I said, knowledge management, I discovered this blog post by Maggie Appleton that was super interesting because she is talking about the term tools of thought which a lot of these different software kind of leveraged in their marketing copy as like, oh, this software will be like the key to evolving your thinking and help you expand making connections, like you mentioned, in ways that you weren't able to before. And was very obviously trying to upsell you on this product, and she -- JOËL: It's over the top. STEPHANIE: A little bit, a little bit. So in this article, I liked that she took a critical lens to that idea and rooted her article in history and gave examples of a bunch of different things in human history that also evolved the ways humans were able to express their thoughts and solve problems. And so some of the ones that she listed were like storytelling and oral tradition. Literally, the written language obviously [laughs] empowered humans to be able to communicate and think in ways that we never were before but also drawings, and maps, and spreadsheets. So I thought that was really cool because she was basically saying that tools of thought don't need to be digital, and people claiming that these software, you know, are the new way to think or whatever, it's like, the way we're thinking now, but we also have this long history of using and developing different things that helped us communicate with each other and think about stuff. JOËL: I think that's something that appealed to me when I was looking at some of these note-taking systems. Zettelkasten, in particular, predates digital technology. The original system was built on note cards, and the digital stuff just made it a little bit easier. But I think also when I was reading about these ideas of keeping ideas small and linking them together, I realized that's already kind of how I tend to organize information when I just hold it in my brain or even when I try to do something like a tweet thread on Twitter where I'll try to break it up. It might be a larger, more complex idea, but each tweet, I try to get it to kind of stand on its own to make it easier to retweet and all that. And so it becomes a chain of related ideas that maybe build up to something, but each idea stands on its own. And that's kind of how in these systems notes end up working. And they're in a way that you can kind of remix them with each other. So it's not just a linear chain like you would have on Twitter. STEPHANIE: Yeah, I remember you all in that episode about note-taking with Amanda talked about the value of having an atomic piece of information in every note that you write. And since then, I've been trying to do that more because, especially when I was doing pen and paper, I would just write very loose, messy thoughts down. And I would just think that maybe I would come back to them one day and try to figure out, like, oh, what did I say here, and can I apply it to something? But it's kind of like doing any kind of refactoring or whatever. It's like, in that moment, you have the most context about what you just wrote down or created. And so I've been a little more intentional about trying to take that thought to its logical end, and then hopefully, it will provide value later. What you were saying about the connectivity I also wanted to kind of touch on a little bit further because I've realized that for me, a lot of the connection-making happens during times where I'm not very actively trying to think, or reflect, or do a lot of deep work, if you will. Because lately, I've been having a lot of revelations in the shower, or while I'm trying to fall asleep, or just other kinds of meditative activity. And I'm just coming to terms with that's just how my brain works. And doing those kinds of activities has value for me because it's like something is clearly going on in my brain. And I definitely want to just honor that's how it works for me. JOËL: I had a great conversation recently with another colleague about the gift of boredom and how that can impact our work and what we think about, and our creativity. That was really great. Sometimes it's important to give ourselves a little bit more blank space in our lives. And counter-intuitively, it can make us more productive, even though we're not scheduling ourselves to be productive. STEPHANIE: Yes, I wholeheartedly agree with that. I think a lot about the feeling of boredom, and for me, that is like the middle of summer break when you're still in school and you just had no obligations whatsoever. And you could just do whatever you wanted and could just laze around and be bored. But letting your mind wander during those times is something I really miss. And sometimes, when I do experience that feeling, I get a little bit anxious. I'm like, oh, I could be doing something else. There's whatever endless list of chores or things that are, quote, unquote, "productive." But yeah, I really like how you mentioned that there is value in that experience, and it can feel really indulgent, but that can be good too. MID-ROLL AD: Debugging errors can be a developer's worst nightmare...but it doesn't have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers that can actually help cut your debugging time in half. So why do developers love Airbrake? It has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking! Airbrake's debugging tool catches all of your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted. In addition to stellar error monitoring, Airbrake's lightweight APM helps developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction. Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality. Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps to include modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back. Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. Head on over to airbrake.io/try/bikeshed to create your FREE developer account today! JOËL: So you mentioned recently that you've had a lot of revelations or new ideas that have come upon you or that you've been able to dig into a little bit more. Is there one you'd like to share with the audience? STEPHANIE: Yeah. So during this downtime that I've had not working on client work, I have been able to keep up a little bit more with Ruby news or just community news in general. And in, I think, an edition of Ruby Weekly, I saw that Ruby 3.2 introduced this new class called data to its core library for the use case of creating simple value objects. And I was really excited about this new feature because I remembered that you had written a thoughtbot blog post about value objects back in the summer that I had reviewed. That was an opportunity that I could make a connection between something happening in recent news with some thoughts that I had about this topic a few months ago. But basically, this new class can be used over something like a struct to create objects that are immutable in their values, which is a big improvement if you are trying to follow value objects semantics. JOËL: So, I have not played around with the new data class. How is it different from the existing struct that we have in Ruby? STEPHANIE: So I think I might actually answer that first by saying how they're similar, which is that they are both vehicles for holding pieces of data. So we've, in the past, been able to use a struct to very cheaply and easily create a new class that has attributes. But one pitfall of using a struct when you're trying to implement something like a value object is that structs also came with writer methods for all of its members. And so you could change the value of a member, and that it kind of inherently goes against the semantics of a value object because, ideally, they're immutable. And so, with the data class, it doesn't offer writer methods essentially. And I think that it freezes the instance as well in the constructor. And so even if you tried to add writer methods, you would eventually get an error. JOËL: That's really convenient. I think that may be an area where I've been a little bit frustrated with structs in the past, which is that they can be modified. They basically get treated as if they're hashes with a slightly nicer syntax to interact with them. And I want slightly harder boundaries around the data. Particularly when I'm using them as value objects, I generally don't want people to modify them because that might lead to some weird bugs in the code where you've got a, I don't know, something represents a time value or a date value or something, and you're trying to do math on it. And instead of giving you a new time or date, value just modifies the first one. And so now your start date is in the past or something because you happen to subtract a time from it to do a calculation. And you can't assign it to a variable anywhere. STEPHANIE: Yeah, for sure. Another kind of pitfall I remember noticing about structs were that the struct class includes the enumerable module, which makes a struct kind of like a collection. Whereas if you are using it for a value object, that's maybe not what you want. So there was a bit of discourse about whether or not the data class should inherit from struct. And I think they landed on it not inheriting because then you can draw a line in the sand and have that stricter enforcement of saying like, this is what a data as value object should be, and this is what it should not be. So I found that pretty valuable too. JOËL: I think I've heard people talk about sort of two classes of problems that are typically solved with a struct; one is something like a value object where you probably don't want it to be writable. You probably don't want it to be enumerable. And it sounds like data now takes on that role very nicely. The other category of problem is that you have just a hash, and you're trying to incrementally migrate it over to some nicer objects in some kind of domain. And struct actually gives you this really nice intermediate phase where it still mostly behaves like a hash if you needed to, but it also behaves like an object. And it can help you incrementally transition away from just a giant hash into something that's a little bit more programmatic. STEPHANIE: Yeah, that's a really good point. I think struct will still be a very viable option for that second category that you described. But having this new data class could be a good middle ground before you extract something into its own class because it better encapsulates the idea of a value object. And one thing that I remember was really interesting about the article that you wrote was that sometimes people forget to implement certain methods when they're writing their own custom value objects. And these come a bit more out of the box with data and just provide a bit more like...what's the word I'm looking for? I'm looking for...you know when you're bowling, and you have those bumpers, I guess? [laughs] JOËL: Uh-huh. STEPHANIE: They provide just like safeguards, I guess, for following semantics around value objects that I thought was really important because it's creating an artifact for this concept that didn't exist. JOËL: And to recap for the audience here, the difference is in how objects are compared for equality. So value objects, if they have the same internal value, even if they're separate objects in memory, should be considered equal. That's how numbers work. That's how hashes work. Generally, primitives in Ruby behave this way. And structs behave that way, and the new data class, it sounds, also behaves that way. Whereas regular objects that you would make they compare based off of the identity of the object, not its value. So if you create two user instances, not ActiveRecord, but you could create a user class, you create two instances in memory. They both have the same attributes. They will be considered not equal to each other because they're not the same instance in memory, and that's fine for something more complex. But when you're dealing with value objects, it's important that two objects that represent the same thing, like a particular time for a unit of measure or something like that, if they have the same internal value, they must be the same. STEPHANIE: Right. So prior to the introduction of this class, that wasn't really enforced or codified anywhere. It was something that if you knew what a value object was, you could apply that concept to your code and make sure that the code you wrote was semantically aligned with this concept. And what was kind of exciting to me about the addition of this to the core class library in Ruby is that someone could discover this without having to know what a value object is like more formally. They might be able to see the use of a data class and be like, oh, let me look this up in the official Ruby docs. And then they could learn like, okay, here's what that means, and here's some rules for this concept in a way that, like I mentioned earlier, felt very implicit to me prior. So that, I don't know, was a really exciting new development in my eyes. JOËL: One of the first episodes that you and I recorded together was about the value of specific vocabulary. And I think part of what the Ruby team has done here is they've taken an implicit concept and given it a name. It's extracted, and it has a name now. And if you use it now, it's because you're doing this data thing, this value object thing. And now there's a documentation page. You can Google it. You can find it rather than just be wondering like, oh, why did someone use a struct in this way and not realize there are some implicit semantics that are different? Or wondering why did the override double equals on this custom class? STEPHANIE: Yeah, exactly. I think that the introduction of this class also provides a solution for something that you mentioned in that blog post, which was the idea of testing value objects. Because previously, when you did have to make sure that you implemented methods, those comparison methods to align with the concept of a value object, it was very easy to forget or just not know. And so you provided a potential solution of testing value objects via an RSpec shared example. And I remember thinking like, ooh, that was a really hot topic because we had also been debating about shared examples in general. But yeah, I was just thinking that now that it's part of the core library, I think, in some ways, that eliminates the need to test something that is using a data class anyway because we can rely a little bit more on that dependency. JOËL: Right? It's the built-in behavior now. Do you have any fun uses for value objects recently? STEPHANIE: I have not necessarily had to implement my own recently. But I do think that the next time I work with one or the next time I think that I might want to have something like a value object it will be a lot easier. And I'm just excited to play around with this and see how it will help solve any problem that might come up. So, Joël, do you have any ideas about when you might reach for a data object? JOËL: A lot of situations, I think, when you see the primitive obsession smell are a great use case for value objects, or maybe we should call them data objects now, now that this is part of Ruby's vocabulary. I think I often tend to; preemptively sounds bad, but a lot of times, I will try to be careful. Anytime I'm doing anything with raw numbers, magic strings, things like that, I'll try to encapsulate them into some sort of struct. Or even if it's like a pair of numbers, it always goes together, maybe a latitude and longitude. Now, those are a pair. Do I want to just be passing around a two-element array all the time or a hash that would probably make a very nice data object? If I have a unit of measure, some number that represents not just the abstract concept of three but specifically three miles or three minutes, then I might reach for something like a data class. STEPHANIE: Yeah, I think that's also true if you're doing any kind of arithmetic or, in general, trying to compare anything about two of the same things. That might be a good indicator as well that you could use something richer, like a value object, to make some of that code more readable, and you get some of those convenient methods for doing those comparisons. JOËL: Have you ever written code where you just have like some number in the code, and there's a comment afterwards that's like minutes or miles or something like that, just giving you the unit as a comment afterwards? STEPHANIE: Oh yeah. I've definitely seen some of that code. And yeah, I mean, now that you mentioned it, that's a great use case for what we're talking about, and it's definitely a code smell. JOËL: It can often be nice as you make these more domain concepts; maybe they start as a data object, but then they might grow with their own custom methods. And maybe you extend data the same way you could extend a struct, or maybe you create a custom class to the point where the user...whoever calls that object, doesn't really need to know or care about the particular unit, just like when you have duration value. If you have a duration object, you can do the math you want. You can do all the operations and don't have to know whether it is in milliseconds, or seconds, or minutes because it knows that internally and keeps all of the math straight as opposed to just holding on to what I've done before, which is you have some really big number somewhere. You have start is, or length is equal to some big number and then comment milliseconds. And then, hopefully, whoever does math on that number later remembers to do the division by 1,000 or whatever they need. STEPHANIE: I've certainly worked on code where we've tolerated those magic numbers for probably longer than we should have because maybe we did have the shared understanding that that value represents minutes or milliseconds or whatever, and that was just part of the domain knowledge. But you're right, like when you see them, and without a very clear label, all of that stuff is implied and is really not very friendly for someone coming along in the future. As well as, like you mentioned earlier, if you have to do math on it later to convert it to something else, that is also a red flag that you could use some kind of abstraction or something to represent this concept at a higher level but also be extensible to different forms, so a duration to represent different amounts of time or money to represent different values and different currencies, stuff like that. JOËL: Do you have a guideline that you follow as to when something starts being worth extracting into some kind of data object? STEPHANIE: I don't know if I have particularly clear guidelines, but I do remember feeling frustrated when I've had to test really complicated hashes or just primitives that are holding a lot of different pieces of information in a way that just is very unwieldy when you do have to write a test for it. And if those things were encapsulated in methods, that would have been a lot easier. And so I think that is a bit of a signal for me. Do you have any other guidelines or gut instincts around that? JOËL: We mentioned the comment that is the unit. That's probably a...I wasn't sure if I would have to call it a code smell, but I'm going to call it a code smell that tells you maybe you should...that value wants to be something a little bit more than just a number. I've gotten suspicious of just raw integers in general, not enough to say that I'm going to make all integers data objects now, but enough to make me pause and think a lot of times. What does this number represent? Should it be a data object? I think I also tend to default to try to do something like a data object when I'm dealing with API responses. You were talking about hashes and how they can be annoying to test. But also, when you're dealing with data coming back from a third-party API, a giant nested hash is not the most convenient thing to work with, both for the implementation but then also just for the readability of your code. I often try to have almost like a translation layer where very quickly I take the payload from a third-party service and turn it into some kind of object. STEPHANIE: Yeah, I think the data class docs itself has an example of using it for HTTP responses because I think the particular implementation doesn't even require it to have attributes. And so you can use it to just label something rather than requiring a value for it. JOËL: And that is one thing that is nice about something like a data object versus a hash is that a hash could have literally anything in it. And to a certain extent, a data object is self-documenting. So if I want to know I've gotten to a shopping cart object from a third-party API, what can I get out of the shopping cart? I can look at the data object. I can open the class and see here are the methods I can call. If it's just a hash, well, I guess I can try to either find the documentation for the API or try to make a real request and then inspect the hash at runtime. But there's not really any way to find out without actually executing the code. STEPHANIE: Yeah, that's totally fair. And what you said about self-documenting makes a lot of sense. And it's always preferable than that stray comment in the code. [laughs] JOËL: I'm really excited to use the data class in future Ruby 3.2 projects. So I'm really glad that you brought it up. I've not tried it myself, but I'm excited to use it in future projects. STEPHANIE: On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeeeeeeee!!!!!!!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Stephanie and Joël attended RubyConf Mini, and both spoke there. They discuss takeaways and highlights from the conference. The core idea for this episode is explained in this article: Constructive vs. Predicative Data (https://www.hillelwayne.com/post/constructive/). This came up recently in a conversation at thoughtbot about designing a database schema and what constraints could be encoded in the schema directly versus needing some kind of trigger or Rails validation to cover it. This episode is brought to you by Airbrake (https://airbrake.io/?utm_campaign=Q3_2022%3A%20Bike%20Shed%20Podcast%20Ad&utm_source=Bike%20Shed&utm_medium=website). Visit Frictionless error monitoring and performance insight for your app stack. RubyConf Mini (https://www.rubyconfmini.com/) Episode on CFP - The Bike Shed 352: Case Expressions (https://www.bikeshed.fm/352) Podcast panel: The Ruby on Rails Podcast Episode 446: I'm Giving A Talk on Thursday (https://www.therubyonrailspodcast.com/446) Slides for FP talk: Functional Programming for Fun and Profit!! (https://speakerdeck.com/jennyshih/functional-programming-for-fun-and-profit?slide=107) Episode on language: The Bike Shed - 356: The Value of Specialized Vocabulary (https://www.bikeshed.fm/356) Constructive vs. Predicative data (https://www.hillelwayne.com/post/constructive/) Avoid the Three-state Boolean Problem (https://thoughtbot.com/blog/avoid-the-threestate-boolean-problem) Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So something that's very recent in both of our worlds has been that both you and I, Stephanie, attended RubyConf Mini, and we both spoke there. What are some of your takeaways or highlights from the conference? STEPHANIE: Seeing you in person was definitely a highlight. I really enjoyed that. Because we're working remotely, I don't, you know, get to be in an office with you day to day. And it was really awesome to hang out with you, I think, for the first time as co-hosts of the podcast. And we both, I think, met some people at the conference too that were listeners. And it was really awesome to share that experience with you. JOËL: I had the interesting experience of several people who told me they recognized me by my voice, which I think is a common thing for podcasters, but as a new host, I was surprised by that. STEPHANIE: Yeah, that's weird. As a podcast listener, too, I definitely know exactly what you're talking about where it's like, oh yeah, I can identify someone by their voice. But to then be that person that people can recognize is pretty weird. I also really enjoyed being an audience member of the podcast panel that you are on at the conference with other podcast folks. It was moderated by Brittany Martin. And yeah, I just thought you represented The Bike Shed really well and spoke for both of us about podcasting in a way that I really appreciated. JOËL: And for any of our listeners who were not able to be there in person, Brittany has published that episode as a podcast, and we will link to it in the show notes. STEPHANIE: Another thing I really liked about RubyConf Mini was the smaller scale. I think it was about 150 or so attendees, which felt very different from traditional Ruby Central conferences with several hundreds of people. I heard a lot from other folks there that they really liked the regional aspect of it, the intimacy of the smaller conference. I think I got more of an opportunity to run into people that I'd met at the conference over the next few days. And there was, yeah, definitely a sense of tighter knit community there, you know, when you meet someone, and then you bump into them on the way into a talk, and then you can ask how their day was going and any highlights that they had. And yeah, I guess I haven't really attended a conference that size before, and so that felt like a very special experience for me. JOËL: I 100% agree. I think the smaller format definitely makes it a little bit more intimate, makes it much easier, I think, to build some of those social connections, to meet with people, and to have some good conversations. I think the format of the conference as well favored that. There were, I think, larger breaks between talks that encouraged people to hang out and talk. And, as you said, because it's smaller, you also get to see the same people over the course of a few different breaks instead of being like, oh, I met a stranger on the morning of day one, and then in the afternoon, I met another stranger. And it's just constantly introducing yourself. One thing that was really interesting to me is the experience of being a speaker is very different than just attending. As a speaker, you get to go to the speaker dinner and connect with a lot of the other speakers there. Some of them might be quote, unquote "famous people" that you're not quite comfortable just walking up to and introducing yourself. But in the smaller dinner, you just find yourself sitting next to them and enjoying some food or a drink and getting conversations. It's also much easier to have people come up to you during the conference. Because you're a speaker, people will come and talk to you. So if you tend to be a little bit more introverted, as long as you can get over your fear of being on stage and public speaking, it actually makes social connection interaction much easier to be a speaker. I would recommend to any of our listeners who were wondering how can I get more out of a conference? How can I get better connections, better conversations? Consider being a speaker. STEPHANIE: Yeah, absolutely. We've talked about this before; I think when we chatted about writing our CFPs for this conference that speaking doesn't have to be a really big, scary thing, but everyone has something to say. I think we had mentioned in previous episodes that your talk topic came out of just a discussion that you had internally, and you were like, wow, enumerables are so cool, like, let me dig deeper into them and just share what I learned. So I totally recommend it. And this conference was my first in real-life speaking opportunity as well, and that felt super different from my experience last time doing it virtually, you know, talking about how much I love that sense of community all the time. But it really felt true for me this time around, where I could see the audience react to the things I was saying, like, maybe go off the cuff a little bit. And then yeah, at the end, having people come up to me was really awesome to just talk about pairing, which is what I spoke about, and just share our experiences. And they asked what I thought about some things, and it was really cool to just be able to spread that knowledge around. And one thing I noticed you did a lot was come up to speakers after they wrapped up their talks. You were almost always the first person to get up and congratulate them and just get the ball rolling on following up on the things they talked about. Is that something that you really enjoy doing or find particularly valuable as an audience member or speaker? JOËL: Yes, both. I think, as a speaker, it's really validating to have people come up to you after the talk and either just tell you they liked the talk or ask a question. I generally don't like to do just open questions after a talk from the audience because then you get the classic; this is more of a comment than a question or people who will tell you that you had a typo on one of your code slides. Like, none of that is useful to anyone. So, if you're really interested, come talk to me afterwards. And then that actually makes me feel like my talk connected with people, and people were paying attention, people enjoyed it, people were learning. So I try to pay that forward as well for talks that I listened to, go up to the speaker, and tell them one thing that I appreciated about the talk or a thing that I learned, or something that got me excited in their content. STEPHANIE: Yeah, I'm sure that it's very appreciated. And it also breaks the awkward silence at the end when the speaker finishes and people aren't sure if it's okay for them to get up and start moving around. Yeah, I thought that was a really good way to kind of just encourage people to start chatting with each other and moving into those break times that we mentioned earlier, those opportunities to socialize. JOËL: Another thing that I think is really fun that you can do at in-person conferences, and I know you were doing it a lot, is going to see the talks of friends and colleagues and sitting in the front row and just being there to cheer them on and encourage them. Again, I think that makes a big difference when you are on stage, and you see these people who are your friends and colleagues there to support you. It gives you that boost of confidence. And when you're there in the audience, it's fun to cheer on somebody else. STEPHANIE: Oh yeah. You gave me a lot of thumbs-ups during my talk, and I really appreciated that. [laughs] So I'm curious if there were any talks that stood out to you that you got to see. JOËL: And I was really inspired by your talk, pair programming. I think there are a lot of things that I can take from that to improve the way I pair. I was also inspired by Aji's talk, Aji Slater, on automating manual tasks that you have to do in an iterative way. That one really hit home because, on my current project, I have been doing a lot of manual things. And I just have random snippets of code, like, some shell script lines or Ruby console lines, that I copy-paste out of Slack conversations because I've shared them with other people who are doing similar work. And I realized that a lot of his advice would apply to the work that I'm doing and how that could really make things better. So that was one of those talks I was listening to, and I was like, oh, you know what? Monday morning, when I go back to my project, this is something that I'm going to start doing. This is something I'm going to change in the way I do my day-to-day work. STEPHANIE: Yeah, absolutely. I have so many tasks that I would like to get automated, and think that one day I will magically have more time in my schedule to get to it. But I liked that his talk gave pretty concrete strategies for baking it into your regular, like you said, day-to-day workflow, and that lowers the activation energy to getting them done. And then those things can be iterated on and could eventually become, in an ideal world, a fully-fledged feature that you put together from doing those repetitive tasks. And yeah, they provide a lot of value not just to you but can eventually provide value to your co-workers and then even your users in the future. JOËL: Were there any talks that stood out for you? STEPHANIE: One talk that I really enjoyed was Jenny Shih's about Functional Programming for Fun and Profit. I have attended a lot of functional programming talks within the Ruby realm, at least to try to get a better sense of how it can apply to my work and the languages and paradigms that I use. And honestly, what I liked about it was that it didn't get too in the weeds about functional programming. What she did was provide mental models for understanding the paradigm that I think was a good vehicle for understanding things very generally. And, for me, like,¬¬ a talk, it's really hard to pay attention to lines of code and to read code on the fly while people are presenting. For me, that is just not how I like to consume that information. And so she provided themes and, like I said, those mental models, which I know you really like to use a lot too in teaching people new concepts. For me, I didn't fully learn what a monad was, once again, but at least having that repeated exposure to those foundational aspects, I think, will eventually lead me to be able to grok those things a little more comprehensively the next time I see it or whenever I decide to dig deeper. JOËL: What was a mental model that was shared that connected with you particularly? STEPHANIE: So one of the main mental models that she shared was thinking about a program in terms of these three dimensions: value, behavior, and time. She had a nice slide that showed the difference between the object-oriented paradigm, where value and behavior are contained by objects, where time is kind of inherently wrapped up in those objects that hold information about the state through values and behavior. Whereas in her functional programming example, those three dimensions were a bit separate. And I found that distinction to be really helpful in separating things that felt very implicit before, but it was nice to see them broken out into very clear concepts in terms of building blocks of a program. JOËL: So it's helpful then when thinking...when you look at code, if you can think about it in those three different dimensions to help think about, am I taking a functional or other approach in this particular dimension when working with this code? STEPHANIE: Yeah, exactly. I think it also gave me more of a vocabulary to describe the pros and cons of each and a lens of thinking about which I might want to choose for the particular problem at hand. JOËL: So you mentioned there's a visual for these three dimensions from the slides. Are those slides publicly available? STEPHANIE: They are. I will link to them in the show notes. JOËL: So all of these talks were recorded. They're not yet available to the public, but I think the plan is to publish them on YouTube sometime in the new year, so that means probably January 2023. And a big shout out to the AV team and everyone who is involved in recording these. STEPHANIE: Yeah, I am definitely looking out for a link to my talk so I can send it to my mom. I also wanted to give a little shout-out to the organizers of RubyConf Mini: Jemma Issroff, Emily Samp, and Andy Croll. JOËL: Woo! STEPHANIE: They put on just a really awesome conference, and I feel very grateful that I got a chance to attend with you, Joël. JOËL: It was definitely a delightful experience. STEPHANIE: Delightful. That's a reference to Joël's talk for those of you who are listening. MID-ROLL AD: Debugging errors can be a developer's worst nightmare...but it doesn't have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers that can actually help cut your debugging time in half. So why do developers love Airbrake? It has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking! Airbrake's debugging tool catches all of your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted. In addition to stellar error monitoring, Airbrake's lightweight APM helps developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction. Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality. Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps to include modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back. Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. Head on over to airbrake.io/try/bikeshed to create your FREE developer account today! JOËL: Coming back from the conference, I recently had a really interesting conversation with some other colleagues at thoughtbot. We were looking at a database schema for a new application and talking about some of the trade-offs involved in how that schema is structured, so what tables we want to have. Do we want to have indexes? Things like that. And particularly around some of the assumptions are business rules that would come into play. So we're looking at...we'd drawn out this Entity Relationship Diagram (ERD). In it, we're looking at all the tables, and something that comes up immediately is like, oh, it's possible to have some bad data that could show up in these columns. Or it's possible that this relationship could exist where this table has a foreign key on this table, but really, that should never happen in this particular way of working. And so then the question became, how do we try to prevent these things that currently the schema allows but that are not valid in this particular business domain? Do we want to change the schema somehow and make that stricter or find some way to prevent it? Do we want to add some kind of validation that will check some business rules first before inserting or updating a record? I'm curious, have you ever been in a situation like that where you had to balance those two approaches to enforcing business rules on your database? A classic small example of this is a situation where let's say, you have a users' table and you have a name column on there. And you want to ensure that that name must always be present; all users must have names. Do you try to enforce that via the schema with a NOT NULL constraint? Or maybe you try to enforce that with a validation, maybe a presence validation at the Rails level. Or if you're really into SQL, maybe some fancy trigger, but do it in a validation style rather than trying to force this using the schema. And our particular scenario was a little bit more complex than just one column; it was more to do with associations. But I think this sort of problem shows up even in constraints as small as a required field. STEPHANIE: That's really interesting. I think that, in my experience, when we are spinning up new tables, at that point, we do try to put some intentional thought into what the schema should look like and what requirements we might need to encode at the database level. But things that are more complex might need a little more code, like Ruby code. I have then pushed to an ActiveRecord validation. One thing that I think is important to know is that when you do set those things on the schema, it's harder to change. And so you usually have to feel pretty confident that that's what you want. Otherwise, you'll run into issues later if that does have to change and making changes to whatever existing data you might have. But it's also pretty common to just do your best when you are deciding on a database schema and then having to make adjustments down the line as you know more about your domain. JOËL: This conversation reminds me a little bit of the idea of database normalization. I think that might almost fit as a subset of general tactics of using the schema to ensure your data is more correct. When you are generating new tables, let's say you're creating a greenfield app and you need to create four or five tables; how much emphasis do you put on database normalization when you're initially designing those? STEPHANIE: I think for a greenfield project when you are setting everything up and creating tables for your main domain models, there is an aspect of it that should be considered because you're in this unique position where nothing really is in existence yet. And you do want to try to set yourself up to be successful and hopefully have information about your main use case for this app and can kind of make decisions about the schema then. At least in my experience, that has been part of the conversation, though, to be fair, because it's so early, you do have the opportunity to change things without as much effort or pain. But I think it's worth considering when you're just sitting down and working through what those models are going to look like. JOËL: And for our listeners who may not have heard the term normalization before, it's a series of...you can think of them as rules that you apply to your database design to try to avoid data redundancies in your tables. There are different levels of this; they're typically referred to as normal forms. So you'll see things like first normal form, second normal form, third normal form; those are kind of the fancy terms for them. But they generally involve breaking out other tables so that you don't have data redundancies. And in many ways, this is similar to principles such as the single-responsibility principle that we apply to objects when we're designing our objects in an OO system. But this is more at the table level for databases. STEPHANIE: I do think that it is so hard, maybe even impossible, to plan something out, to not have any of those redundancies, to begin with. And I do think sometimes they are a bit inevitable. But I also have had the experience of having to figure out what the heck I'm looking at when I am querying data and see all these things that are duplicated or maybe slightly different. And yeah, I think when you are in that position of starting a greenfield application, it is really interesting to see how you make those decisions about what needs to be enforced and where. Where did you end up landing, or what did you discuss in this conversation with the co-worker? JOËL: I think we went with a bit of a hybrid approach. Some things, we can use the schema to prevent bad data, and then some things either cannot be represented with a schema, or it's possible, but it's really cumbersome and painful. And so, we chose to try to enforce it with a validation. To me, this feels very similar to a problem in typed languages. So some communities that use a lot of types try to use those types to only allow data to come through that's in a valid shape. And so you'll hear things like make impossible states impossible or make illegal states unrepresentable. And that works for many things, but it's not always possible to enforce all of your business constraints through a schema. Or sometimes it's possible but just not practical. And so, I think there is a balance of finding when you can use the schema or when it's better to use the validation.¬ STEPHANIE: Yeah, I think my general rule of thumb is, like I mentioned earlier, things I feel really confident about that we want to make sure that we have in our database or in our data for sure. I do lean towards requiring those in a schema, and it also communicates that confidence or communicates that intent that it's something that at one point was decided is important. And so, if a future developer comes in, it would take a lot of work for them to write a migration, to remove some database constraint. Whereas I think sometimes validations at the Rails level are potentially a little more open to change and then even more so if you get to validating on the client side. JOËL: That can get to be a really, like, it's a useful tool, but one that you can really hurt yourself with. If you modify your validations at the Rails level or at the front-end level, but then you don't backfill those changes on your data in the database, then you might have records in your database that if you were to load them into memory and hit save on them again, would refuse to save because they no longer match the validations. And on longer-lived applications, I've seen that happen sometimes where not all rows in the database pass the Rails validations. STEPHANIE: Yeah, I think I've seen that be a problem either for developers who then have to backfill that data or write some migration to change some of the data to meet the new requirements, or just unexpected bugs on the users who discover something new but like you said, have been there long enough before those things were implemented. JOËL: The more I think of this, I think maybe constraints that are enforced at a validation level might still require changing the data in your database. So if you had a constraint enforced via a schema, you don't have a choice. You have to write some way to migrate that data so that it fits the new schema. You can kind of lie to yourself with validation and not change the historic data, and sometimes that is the case; you want to keep the old data and only prevent new data from being written in the old format. But if you need consistency, then you probably need a data migration regardless of which approach you take. STEPHANIE: Yeah, that definitely sounds like the more robust way to go about it for sure. JOËL: I have an article that I like to reference a lot by Hillel Wayne on Constructive Versus Predicative Data, which is basically looking at these two general approaches to enforcing data correctness and formalizing them a little bit. So do you try to enforce them based on the construction or the shape of the entity that you're creating, be that a database table, an object, a type, something like that? Or do you enforce it via some kind of predicate? So that could be a validation or other similar logic that runs kind of at runtime to enforce your constraints. STEPHANIE: That's interesting. I hadn't heard of those terms before, but I think they provide a lens through which you can look at the problem. Did the article end up suggesting different strategies for solving that problem, or was it more theoretical in different ways to look at it? JOËL: I think the article does two things. First, like you said, it gives us the words to talk about those approaches. And having those labels now, I start seeing them everywhere. I see them in databases, I see them in objects, I see them when doing types across a variety of languages. So that's already a huge win for me. I think you and I had done an episode a couple of months back where we talked about the value of having labels to put to ideas. And I think for me reading that article gave me those two labels. And all of a sudden, it really helped to make connections that I wasn't seeing before. The second thing that the article does is, I think, explore some of the limitations that each approach has and when you might want to use one versus another. The constructive approach, so using a schema, is more consistent because you know it is impossible for the program to create data that's in the wrong shape. That being said, not all constraints can be represented in a constructive manner, or it might be possible but really cumbersome. Also, sometimes it's not really invalid data; it's just sort of undesirable data. So you might want a looser schema. And let's say that you're storing some kind of intermediate state or some kind of raw input from another system that you might want to layer validations on top of, but you don't want to reject that data out of your database. You want that sort of incomplete or imperfect data in your system. Something that I find myself doing more and more these days when I create new tables is to really lock down the schema as much as possible. I think that might be contrary to maybe the way a lot of people in the community like to work. Some people might prefer to start with a very loose schema with no constraints and then work towards making things stricter as they explore the domain, and that's kind of the default that Rails has. If you're creating a new table, all columns, for example, are nullable by default. Personally, I will put a null false on every column and every migration that I make unless somebody can make a convincing case otherwise, and even then, I might try to think of is there any possible way that we could avoid that scenario and put that null false. Part of the reason for that is that it is much easier to loosen constraints on existing data than to tighten them afterwards. So if I have a column where no value is allowed to be null, and then later on we decide, you know what? It is okay for some of them to be null, I can change the requirement on that column, and I don't need to make any changes to the existing data. It just works. If the reverse happens, if I have a column that allows a bunch of nulls and then I want to make that column required, now I have to go and find a way to backfill all the empty spots in that column. And that could be a very challenging process. It might even be impossible. There might be some values there that it's just like, the user did not supply them at the time because we didn't ask for them. And now there's nothing we can put in there. So do you put in, like, unknown or not available? Then you have to ask yourself some really difficult questions about your data. STEPHANIE: Yeah, absolutely. I think I agree with you there. Another thing I like to do is provide default values for columns, especially ones where they can't be null, because, like you were saying, that helps me have a better understanding of just what is going on in the database. An issue I have seen come up involves a Boolean column where if a default value of false, for example, if that's what we're going with, is not encoded in the schema, you end up with potentially three values for a Boolean, which would be true, false, and null, and that I think has been -- JOËL: The infamous three-state Boolean. STEPHANIE: Yeah, exactly, the three-state problem, which is just inherently contradictory to what a Boolean is, to begin with. And I've definitely run into issues with that where you have to decide, or figure out, or write code to determine is null false? Is that what we mean here? It's not clear. But if you, like you said, locked it down at the beginning, provided those default values, that puts in those guardrails to prevent things from getting out of hand. JOËL: It also makes it easier for users of your database, application, whatever to interact with your code. I've run into this a lot when working with GraphQL APIs. And the default in many GraphQL server implementations is to make all fields nullable by default. When you build your schema, you have to add some extra things there to say, "This field is non-nullable," which means that a client that's now consuming it, anytime they deal with the data they need to check, is it present or not? You can't have the confidence that that data is there. And so it can force a lot of extra checks on the client. Or I guess you could just take it on faith and hope nothing breaks. STEPHANIE: Yeah, it's funny you mention that because I definitely think there's like spheres of impact. So as a developer, you maybe start having to write code that checks those kinds of things, like if it's null or not in your code. Then that can even extend to, like you said, your users or consumers of the API, who then have to contend with data that they have no control over. And I've been there too, and that can be frustrating as well. JOËL: We've talked a lot about data correctness and different ways to achieve it, different strategies. Why is this something that we care so much about? STEPHANIE: I think data correctness is really important from a developer experience perspective. And it's way easier to fix a bug in your code than it is to wrangle a lot of accumulated bad data. JOËL: Yeah, sometimes bad data is not fixable at all, and those are situations where you have a really bad day as a developer. STEPHANIE: Agreed. JOËL: Well, on that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.
Inspired by a Slack thread, Joël invites fellow thoughtbotter Aji Slater on the show to talk about when you should use class methods and when you should avoid them. Are there particular anti-patterns to look out for? How does this fit in with good object-oriented programming? What about Rails? What is an "alternate constructor"? What about service objects? So many questions, and friends: Aji and Joël deliver answers! Backbone.js collections (https://backbonejs.org/#Model-Collections) Query object (https://thoughtbot.com/blog/a-case-for-query-objects-in-rails) Rails is a dialect (https://solnic.codes/2022/02/02/rails-and-its-ruby-dialect/) Meditations on a Class Method (https://thoughtbot.com/blog/meditations-on-a-class-method) Why Ruby Class Methods Resist Refactoring (https://codeclimate.com/blog/why-ruby-class-methods-resist-refactoring/) Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. And today, I'm joined by fellow thoughtboter Aji Slater. AJI: Howdy. JOËL: And together, we're here to share a little bit of what we've learned along the way. So, Aji, what's new in your world? AJI: Yeah, well, I just joined a new project, so that's kind of the newest thing in my day-to-day work world. I say just joined, but I guess it was about a month ago now. I'm on the Liftoff team at thoughtbot, which is different than the team that you're on. We do more closer to greenfield ideas and things like that. So there's actually not much to speak about there in that project just yet. Rails new is still just over the horizon for us. So I've been putting a lot of unused brain cycles toward a side project that is sort of a personal knowledge base concept, and that's a whole thing that I could probably host an entire podcast about. So we don't have to go too deep into my theories about that. But suffice it to say I've talked to some other ADHDers like myself who find that that space is not really conducive to the way that we think and have to organize ourselves and our personal knowledge stores. So sort of writing an app that can lend itself to our fast brains a little bit better. JOËL: Nice. I just recently recorded an episode of this podcast talking a little bit about note-taking approaches and knowledge-base systems. So, yeah, it's a topic that's very much top of mind for me right now. AJI: Yeah, what else is going on in your world? JOËL: I'm based in New England in the U.S. East Coast, and it is fall here. I feel like it happened kind of all of a sudden. And the traditional fall thing to do here is to go to an orchard and pick apples. It's a fun activity to do, and so I'm in the middle of planning that. Yeah, it's fun to go out into nature, very artificial space. AJI: [laughs] JOËL: But it's a fun thing to do every fall. AJI: Yeah, we do that here too. There's an orchard up north of us where my wife and I live in Chicago that we try to visit. And Apple Fest in Lincoln Square is this weekend, and we've been really looking forward to that. Try another time at making homemade hard cider this season, I think, and see how that goes. JOËL: Fun. When you say another time, does that mean there was a previous unsuccessful attempt? AJI: Yes. Did the sort of naive approach to it, and there is apparently a lot more subtlety to cidermaking than there is home-brew beer. And we got some real strong funk in that cider that did not make it necessarily an enjoyable experience. Like, it worked but wasn't the tastiest. JOËL: So it got alcoholic. It was just terrible to drink. AJI: Yeah, I would back that up. JOËL: So recently, at thoughtbot, we had a conversation among different team members about the use of Ruby class methods, when they make sense, when they are to be avoided. What is their use case? And different people had different opinions. So I'm curious what your take on class methods are. When do you like to use them? AJI: Yeah, I remember those conversations coming up. I think I might have even started one of those threads because this is something that comes up to me a lot. I'm a long-time listener, first-time caller to The Bike Shed. [laughs] I can remember awaiting new episodes from Sage and Derek to listen to on my way to and from my first dev job. And at one point, Sage had said, "Never put your business logic in something that you can't call .new on." And being a young, impressionable developer at the time, I took that to heart, and that seems something that just has been baked in and stayed very truthful to me. And I think one of the times that I asked that and got some conversation started was I was trying to figure out why did I feel that, and like, why did they say that? And I think, yeah, I try to avoid them. I like making instances of things. What is your stance on the Class Method, capital C, capital M? JOËL: I also generally avoid them. I have sort of two main scenarios that I like to use class methods, first is as an alternate constructor. So new is effectively a class method that's built into Ruby's object model. But sometimes, you want variations on your constructor that maybe sets values by default or that construct things with some slightly different inputs, things like that. And so those almost always make sense as class methods. The other thing that I sometimes use a class method for is as an alias for newing up an instance and then immediately calling an instance method on it. So it's just a slightly shorthand way to call some code. AJI: That's usually been my first line defense of when there's someone who might feel more comfortable doing class methods that sees me making an instance and says, "Well, you don't need an instance, just make a class method here because it'll get too long if you have to .new and then dot this other thing." And so I'll throw in that magic little trick and be like, here you go. You can call it a class method, and you still get all the benefits of your instance. I love that one. JOËL: Do you feel like that maybe defeats the purpose? In terms of the interface that people are using, if you're calling it a class method, do you lose the benefits of trying to do things at the instance level instead? Or is it more in the implementation that the benefits are not at the caller level? AJI: I think that's more true that the benefits are at the instance level, and you're getting all of that that goes along with it. And you're not carrying along a lot of what I see as baggage of the class method version, but you're picking up a little bit of that syntactic sugar. And sometimes it's even easier just to conceptualize, especially in the Rails space because we have all of these different class methods like, you know, Find is one I'm sure that we use all the time to call it on a class, and we get back an instance. And so that feels very natural in the Rails world. JOËL: I think you could make an argument that that is a form of alternate constructor. It's a class method you call to get an instance back. AJI: Yeah, absolutely. JOËL: The fact that it makes a background request to the database is an implementation detail. AJI: For sure. I agree with that. I had a similar need in a recent project where the data was kept on a third-party API. So I treated it the same way as, instead of going out to the database like ActiveRecord does, made a class method that went off to the API and then came back and made the object that was the representation of that idea in our application. So, yeah, I wholeheartedly agree with that. JOËL: So in Rails, we have the scope keyword, which will run some query to get a collection of records. But another way that they're often implemented is as class methods, and they're more or less interchangeable. How do you feel about that kind of use of class methods on an ActiveRecord object? Does that violate some of the ideas that we've been talking about? Does it sort of fit in? AJI: I think when reaching for that sort of need, I sort of fall into the camp of making a class method rather than using a scope. It feels a little less like extending some basic Rails functionality or implying that it's part of the inherent framework and makes it a little more like behavior that's been added that's specific to this domain. And I think that distinction comes into my thinking there. I'm sure there are other reasons. What are your thoughts there? Maybe it'll spark an idea for me. JOËL: For me, I think I also generally prefer to write them as class methods rather than using the scope keyword, even though they're more or less the same thing. What is interesting is that, in a way, they kind of feel like alternate constructors in that they don't give you an instance; they give you back a collection of instances back. So if we bend the rules a little bit...these are not hard and fast rules but the guidelines. If we bend the guidelines a little bit, they kind of fit under the general categories for best uses of class method that we discussed earlier. AJI: Yeah, I can definitely see that. I tend to think, or at least I think when you had first brought up the term of alternate constructors, my first thought was of one instance; you ask for a thing, and it gives you this thing back. But it's the same sort of idea with that collection because you're not getting just one instance; you're getting many instances. But it's the same kind of idea. You've asked the larger concept of the thing, the class, to give you back individuals of that class. So that totally falls in line with how I think about acceptable uses of these class methods the way that we've been talking about them. JOËL: Rails is something really interesting where a lot of the logic that pertains to a single item will live at the instance level. And then logic that pertains to a group of items will live at the class level. So you almost have like two categories of operations that you can run that semantically live either at the class or the instance level. Have you ever noticed that separation before? AJI: I think that separation feels natural to me because I came into programming through Rails. And I might have been colored in my thinking about this by the framework. The way that I conceptualize what a class is being sort of this blueprint or platonic ideal of what an individual might be and sort of describing the potential behaviors of such an individual. Having that kind of larger concept be able to work across multiple instances feels, yeah, it feels sort of natural. Like, if you were to think about this idea of a chair, then if you went in and modified what a chair is to mean, then any chair that you asked for later on would kind of come with that behavior along with it. Or if you ask for several chairs, they would all sort of have that idea. JOËL: I think similar to you; I had that outlook on that's almost like a natural structuring of things. And then, years ago, I got into the hot, new JavaScript framework that was Backbone.js. And it actually separates...it has like a model for individual instances, and then a separate kind of model thing for collections. And that kind of blew my mind. But what was interesting, then, is that you effectively have instance methods that can deal with all things collection-related, any sort of filtering, any sort of transformations. All of those are done, which you have an instance of a collection, basically, that you act on. And I guess if we were trying to translate that into Rails, that's almost like the concept of a query object. AJI: Hmm, it's sort of an interesting way to think about that. And Backbone, I feel like I did a day of that in bootcamp. But it has been some time, so I'm not sure that I've worked with that pattern specifically. But it does sort of bring up the idea of how much do you want to be in one model class? And do you want it to contain both of these concepts? If you have a lot of complex logic that is going to be dealing with a collection, rather than putting that in your model, I think I would probably reach for something like a service object that is going to be specifically doing that and sort of more along that Backboney approach maybe like a query object or something like that. JOËL: Interesting. When you use the term service object, do you mean something that's not a Rails model, just in general? Or are you talking specifically about one of these objects that can respond to call and is... I've heard them sometimes called Command objects or method objects. AJI: Yeah, that's an overloaded term certainly in the real space, isn't it? Service object, and what does that mean? I think generally, when I say it, I'm meaning just a plain, old Ruby object like something that is doing its one thing. You're going to use it to do its implementation details. They're all kind of hidden behind in private methods and return you something useful that you can then plug into what you were doing or what you need going on in some other place in your app. So it, to me, doesn't imply any specific implementation of, like, do you have call? Do you use it this way? Do you use it that way? But it's something that's kind of outside of it is either a model, a view, a controller, and it encapsulates some kind of behavior. So whether that, like we're saying, is a filtering or, you know, it's going to wrap that up. JOËL: I see. So, for you, a query object would be a service object. AJI: Yeah, I think so. You know, maybe this is one of the reasons why I generally don't like the overuse of the term service object in our space. I don't know if that's a hot take, and I'm going to get emails for this. But -- JOËL: Everybody send your angry tweets @Aji. AJI: Yeah, do it to @Aji on Twitter because I've been trying to get that three-letter handle for years. No, but if you want to talk to me, I'm @DoodlingDev. But, yeah, certainly, it does feel sometimes like an overloaded term, and I just want to go back to talking about plain, old Ruby objects. JOËL: So, service object is definitely an overloaded term. It's used for a lot of things. One thing that I've often seen it referring to are objects that respond to call. And just to keep away the confusion, maybe let's call them Command objects for the purposes of this conversation. AJI: Sounds good. JOËL: I commonly see them done where the implementation is done with a class method named call. Sometimes it delegates to an instance that also has call. Sometimes it's all implemented as a class method. How do you feel about that pattern? AJI: I don't mind the idea of a thing that responds to call. It, in a way, sort of implies that the class is sort of named as an action, which I don't like. It has an er name, and that kind of has a class named as a pattern. And that always sort of bugs me a little bit. But what I hope for when I open up one of those sorts of classes or objects is that it's going to delegate to an instance because then you're, again, picking up all of those wonderful benefits of the instance-level programming. JOËL: You keep mentioning the wonderful benefits of instance-level programming. What are some of those benefits? AJI: One of the ones that sort of strikes me most visibly or kind of viscerally when I see it is that they're very easy to understand. You can extract methods pretty easily that don't turn into kind of clumsy code of a bunch of different class methods that all have four arguments passed in because they're all operating on the same context. And when you're all operating on the same context, you have really a shared state. And if you're just passing that shared state around, it just gets super confusing. And you get into the order of your arguments, making a big impact on how you are interacting with these different things. And so I think that's sort of the first thing that comes to mind is just visually noisy, which for me is super hard to get my head around, like, well, how am I supposed to use this thing? Can I extend it? JOËL: Yeah, I would definitely say that if you have a group of class methods that all take, commonly, it's the first argument, the same piece of data and tries to operate on it, that's probably a code smell that points to the fact that these things want to be an instance that lives around it. This could be a form of primitive obsession if you're passing around, let's say, a hash, all of these, and maybe what you really want is to sort of reify that hash into an object. And then all these class methods that used to operate on the hash can now become instance methods on your richer domain object. AJI: Yeah. What do you say to the folks that come from maybe a more functional mindset or are kind of picking up on the wave of functional programming that's out there in the ethos that say that you've got a bunch of side effects when you don't have everything that your method is operating on, being passed on or passed in? JOËL: I think side effect is a broad term. You could refer to it as modifying the internal state of an object. Technically, mutation is a side effect. And then you have things like doing effects out in the outside world, like making an HTTP query, printing to the screen, things like that. I think those are probably two separate concepts. Functional programming is great. I love writing functional code. When you're writing Ruby, Ruby is primarily an object-oriented language with some functional aspects brought in. In my opinion, it's very, you know, a great combination of the two. I think they've gotten the balance well so that the two paradigms play nicely together rather than competing. But I think it's an object-oriented language first with some functional added in. And so you're not going to be, I mean, I guess you could; there is a way to write Ruby where everything is a lambda or where everything is a class method that is pure and takes in inputs. But that's not the idiomatic way to write Ruby. Generally, you're creating objects that have some state. That being said, if an object is mutating a lot of global state, that's going to become problematic. With regards to its internal state, though, because it is very much localized and it's private, nobody else gets to see it; in many ways, an object can mutate itself, and that chain stays pretty local. AJI: Yeah, absolutely. You've tripped onto another one of my favorite rabbit holes of idiomatic code, and, like, what does that mean, and why should we strive for that? But I absolutely agree that when Ruby is written to conform to other paradigms that aren't mostly object-oriented is when it starts to get hard to use. It starts to feel a little off. Maybe it has code smells around it. It's going to give me the heebie-jeebies, whatever that might mean for you or for different developers. I think we all have our things that are sort of this doesn't feel right. And you kind of dig into it, and you can sort of back that up. And whenever Ruby starts to look like something that isn't lots of little objects sending messages, is when I start to get a little on edge, maybe. JOËL: It is worth, I think, calling out the fact that Ruby is a very expressive language. And there are effectively many...you could call them dialects of it. You have sort of your pure sort of OO approach. You have what's typically written in Rails, which has some OO things. But Rails is also, in many ways, it's very DSL-heavy and, in some ways, very class method-heavy. So writing Rails is sort of its own twist on Ruby. And then, some people will try to completely retrofit a functional approach onto Ruby, and that's also a way that some people like to write their code. And some of these, you can't necessarily say they're not valid, but they're not what you'll mostly see in the wild. And they're not necessarily the approach that I would recommend. AJI: Yeah, that's the blessing, and the curse of both programming in general and such an expressive language like Ruby is that there are many different valid ways to do it. And what are your trade-offs going to be when you make those choices? I think that falls kind of smack dab into that idiomatic conversation. And it comes up for me, too, as a consultant because I try to tend towards that idiomatic, those common patterns and practices because I'm not going to live with this code forever. I need to hand this off. And the closer it is to what you might see out there in the wild more commonly, the easier it will be for the next Ruby developer to come pick it up and extend it. JOËL: So you'd mentioned earlier some of the benefits of instance programming. One of the things that I find is maybe a little bit weird when you go heavily into the class method approach is that there is only one instance of the class, and it is globally available. AJI: Are you talking about a singleton there? JOËL: Yes. And, in fact, your class is effectively a singleton, potentially with globally mutable state. I hope not, but potentially with all of the gotchas and warnings that that entails. And so, if you think of your user instance, you need a reference to it, and there can be multiple of them, and you can call methods on them. If everything is happening at the class level, there is a single user class in memory shared by anyone who wants to use it. It's globally accessible. You can all call methods on it. Yeah, in many ways, it does act like a singleton. AJI: And let's not even get into the Ruby chestnut of everything's an object. So it is an instance of a class in and of itself. JOËL: Yes. AJI: But, absolutely, it can start to act that way. But the singleton it's enshrined in the Gang of Four book of patterns. Like, so what's wrong about a singleton? I hope you can understand over the airwaves the devil's advocate that I'm playing here. [laughs] JOËL: Yes. There are little horns that have sprouted on your head right now. I think part of the problem with singletons is that, generally, they are globally accessible. There's the problem of global mutable state again. There was a time, I think, when the OO community went pretty wild with singletons, and people realized that this was not great. And so, over time, a consensus evolved that singletons are a pattern that, while useful, should be used rarely and in moderation. And a lot of warnings have been shared in the community, like, be careful not to overuse the singleton pattern or don't build your system out of singletons. And maybe that's what feels so weird about a system that's built primarily in terms of class methods for me is that it feels like it's built out of singletons. AJI: Yeah. When I think of object-oriented programming, I kind of fall back to maybe one of the ideals of it is that it represents the world more accurately or maybe more understandably. And that sort of idea doesn't fit that paradigm, does it? If you're a factory that is making widgets, there's not the one canonical widget that all of your customers are going to be talking to and using. They are going to each have their own individual widgets. And those customers can be thought of like the consumers of your methods, your objects. JOËL: The idea being the real-world thing you're simulating normally, there are multiple actors of every type rather than a single sort of generic one that stands in for everybody. AJI: If this singleton is going to be your interface or the way that you interact with each of these things that are conceptually different, like a user or something like that, then differentiating between which user becomes a lot harder to do. It takes a lot more setup and involved process in referring to this user when and that kind of thing and creating the little instances. Then you've got more kind of direct reference to a single concept, a single individual. JOËL: So what you've described is a very sort of classic OO mindset. You find the data and the behaviors that go together. You try to oftentimes simulate the world, model it in terms of actors that give and receive messages. In many ways, though, I think when you're building a system out of class methods, you're thinking about the world in an almost different paradigm. In many ways, it feels almost procedural. What are the behaviors that need to happen in my app? What are the things that need to be done? You'd mentioned earlier that oftentimes these classes or the methods on them will end up with E-R; they're all verbs. You have a thing-doer, a thing executor, thing manager. They all do things rather than having domain concepts extracted and pulled out. Would you say that that feels somewhat procedural to you as well? AJI: Yeah. I think a great way to divide it is the way that you have right there; it's these sorts of mindsets. Do you have collections of things that have behaviors, or do you have collections of behaviors that might refer to things? And where you're approaching the design of a system, either from that behavior side or from that object side, is going to be a different mindset. Procedural being more focused on that kind of behavior and telling it what to do rather than putting... I think this is probably a butchered Sandi Metz example, but putting your roommate who hates cats and a cat that doesn't want its tail stepped on in one room, and eventually, things will happen accordingly. And those two mindsets are going to end up with very different architectures, very different designs, very different ways of building these applications that we make. And, again, does that come back to...Ruby, potentially to a lesser extent but still in the same camp, is object-oriented language, and it sort of functions best when considered and then constructed in that mindset. And I often wonder sometimes if language developers and language designers make anti-patterns sort of purposefully awkward to use. Like, if you want to hide a lot of class methods, you can do the class shovels self version of things or have privateclassmethod littered all the way through your file. And it seems to me like that might be a little bit of a flag that, like, hey, you're working against the system here. You're trying to make it do a thing that it doesn't naturally want to do. JOËL: Yeah, because you'd mentioned this private_class method thing because, by default, it's hard to get class methods to be private. You have to use a special keyword. You can't just write private in the class and then assume that the methods below it are going to be private because that does not apply to class methods. AJI: Exactly. And that friction to making an object that has a smaller interface, that kind of hides its implementation, seems as though it's a purposeful way that Ruby itself was designed to maybe nudge us, developers, into a certain way of working or suggesting a certain mindset. JOËL: There's a classic Code Climate article titled Class Methods Resist Refactoring. And it mentions different ways that when you're relying heavily on class methods, it's harder to do some of the traditional refactors things like just extract method because it is clunkier because you can't have private methods as easily. You can't share state, so you have to thread variables through. I guess, technically, you can share state with things like class variables and class instance variables, but if you do that, you will probably be very sad. AJI: [laughs] Yeah, you're opening yourself up to a whole world of hurt there, aren't you? And, yeah, you're opening yourself up to a whole world of hurt there with that, aren't you? Sort of sharing data so dangerously around your app. JOËL: So I'm a big fan of test-driven development. And one of the things that TDD believes in is that test pain should help guide the design of your system and that, generally, things that are easier to test are better designed. AJI: Yeah. JOËL: It's often easier to test class methods because they are globally available singletons. I can easily stub a class. Whereas if I need to stub an instance, I need to do some uglier things like stub any instance of or stub the constructor to return a double, or do some other kind of dirty tricks like that. Does that mean that TDD would prefer a class method-based approach to writing code? AJI: I think that a surface-level reading of that might say that it does. And I think that maybe the first pass on things, if you're thinking about I want to get this thing done that's right in front of me right now and just move forward, might kind of imply that. But if you start to think about or have come back to something that was implemented in that way, anytime that sort of behavior is going to grow or change, then it's going to start to...the number of backflips that you have to do become a lot more complicated and a lot higher when you've got class methods. Because I find that, yes, you might have to stub out or pass in a created object or something like that. But if you've got a class method, especially if it is calling other class methods inside it, then all of a sudden, you have in your test this setup that looks completely unrelated to anything that you're running and testing, that you have to have all of this insight or knowledge of what those classes are doing just to set up your test framework before you can even run that. Another thing that is looked to as an axiom when writing tests that can imply this class approach is that you shouldn't change your code just for the test. If you're doing dependency injection or something like that, passing around little objects, then you're making your code more complicated to make your tests look a certain way. JOËL: That's interesting. So maybe I'm reacting to some test pain by trying to change my tests first. So I'm trying to deal with some collaborators, and it is tricky to do. And so I decide, well, the thing I want to do is I want to reach for stubbing. But then that's hard to do because it's instances. So in order to make already that compromise in my test work better, now I change the code to be nicer for the test to use mostly classes because those are global. Whereas maybe the correct path to take initially is, say, oh, there isn't test pain here because I'm trying to isolate an object from its collaborators. Maybe we need to pass an object in as an argument rather than hard coding it inside the class. AJI: Yeah, absolutely. JOËL: So I guess you follow the test pain, but maybe the problem is that you've already kind of gone down a path that might not be the best before you got to the point where you decided that you needed a class method. AJI: And I think that idea of following the test pain can be, again, there are only shades of gray; there is no black and white. It can be sort of taken in a lot of different ways. And the way that I think about it is that test pain is also sort of an early warning sign that there's going to be pain if you want to reuse this class or these behaviors somewhere else. And if it was useful somewhere, it's likely it's going to be useful in another place. And there are many different kinds of tests pain. The testing is a little easier with a class method because you're not stubbing out any instance of. You're just stubbing; really, what's the difference between stubbing out any instance of or stubbing out the class? Is that just a semantic difference? Is that -- JOËL: Because someone on the internet said that stubbing any instance of is bad. AJI: Ooh, right, the internet. I should have read that one. The thing that you can do with passing around instances or sending messages to instances as you do when you're calling a method is that you can easily swap in a different object if you need to stub it. It's similar to how you can change the implementation under the hood of an object and pass in an object that responds to the same messages and kind of keep moving forward with your duck typing. If you can go into your tests and pass it sort of an object that's always going to return a thing...because we're not testing what that does; we just need a certain response so that we can move forward with the pathway that is under test. You can do that in so many different ways. You could have FactoryBot, for instance, give you a certain shape of a thing. You can create a tiny, little class right there in your tests that does something specific, that can be easily understood what's going on under the hood here. And instead of having to potentially stub out or create all of these pathways that need to be followed that are overwriting logic that's happening in different class methods or different places otherwhere in the application, you can just pass in this one simplified thing to keep your tests sort of smaller and easier to wrap your head around all in just one go. JOËL: I think what I'm getting here is that when you design your code around instances, you're more likely to build it in a modular way where you pass objects to other objects. And when you build your code using class methods, you're more likely to write it in a hard-coded way. Because you have that globally available class, you just hard-code it and then call it directly rather than passing things in. And so things end up more coupled and, therefore, high coupling leads to more test pain. AJI: Yeah, I think you've really kind of hit on something here that the approach of using class methods is locking that class into kind of a single context or use case. Usually, it is this global thing that is this one way, and that's even kind of backed up by the fact that class methods are load-time logic instead of run-time logic. And it really kind of not only couples but it makes it more brittle and less amenable to kind of reuse. JOËL: That's a really interesting distinction. I often tend to think of runtime versus load time in terms of composition versus inheritance. Composition, you can combine objects together at runtime and get behaviors built on the fly as the code is executing, whereas inheritance sort of inherently freezes you into a particular combination of behaviors at the time of loading the code. It's something that the programmers set up, and so it is much less flexible. And that is one of the arguments why the Gang of Four patterns book recommends composition over inheritance in many situations is because of that runtime versus load time dichotomy. And I hadn't made that connection for class methods versus instance methods, but I think there's a parallel there. AJI: Yeah, absolutely. The composition versus inheritance thing, I think, goes very hand in hand with the conversation that we're having about putting your behavior on a class versus an instance because...and I don't know if this is again yielding my thoughts to 'the internet said' in that composition is preferable to inheritance. But without unpacking that right there, that is certainly something that I strive for as well. And while it might have, much like TDD, some kind of superficial, short-term complexity, it has long-term payoff in that flexibility and that reuse, and that extensibility, and all of those other buzzwords that we developers like to throw around. JOËL: So you've shared a lot of thoughts on the use of class methods. I think this could branch into so many other aspects of object-oriented design that we haven't looked at or that we could go deeper, things like TDD. We could look into how it works with the solid principles, all sorts of things. But I think the big takeaway for me is that class methods are very useful, but it's easy to use them as our single hammer to every problem being a nail. And it's good to diversify your toolset. And some tools are specialized; they're good to be used in very specific situations that don't come across very often, and others are used every day. And maybe class methods are the former. AJI: Absolutely. That hammer-and-nail metaphor was right where I was headed for too. Love it. JOËL: Well, thank you so much, Aji, for joining the conversation today. Where can people find you online? AJI: Yeah, anywhere you want to look for me: Instagram, GitHub, Twitter. I'm @DoodlingDev, so just send all your angry emails that way. JOËL: And with that, let's wrap up. The show notes for this episode can be found at bikeshed.fm. This show is produced and edited by Mandy Moore. If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. If you have any feedback, you can reach us at @_bikeshed, or reach me at @joelquen on Twitter, or at hosts@bikeshed.fm via email. Thank you so much for listening to The Bike Shed, and we'll see you next week. Byeeeeee!!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.