Jeremy Wood, Author at ProdSens.live https://prodsens.live/author/jeremy-wood/ News for Project Managers - PMI Wed, 07 Feb 2024 12:20:30 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.5 https://prodsens.live/wp-content/uploads/2022/09/prod.png Jeremy Wood, Author at ProdSens.live https://prodsens.live/author/jeremy-wood/ 32 32 The 15 Best WordPress Email Plugins in 2024 https://prodsens.live/2024/02/07/the-15-best-wordpress-email-plugins-in-2024/?utm_source=rss&utm_medium=rss&utm_campaign=the-15-best-wordpress-email-plugins-in-2024 https://prodsens.live/2024/02/07/the-15-best-wordpress-email-plugins-in-2024/#respond Wed, 07 Feb 2024 12:20:30 +0000 https://prodsens.live/2024/02/07/the-15-best-wordpress-email-plugins-in-2024/ the-15-best-wordpress-email-plugins-in-2024

If you’re on the lookout to enhance your business blog with an email newsletter, using a WordPress email…

The post The 15 Best WordPress Email Plugins in 2024 appeared first on ProdSens.live.

]]>
the-15-best-wordpress-email-plugins-in-2024

If you’re on the lookout to enhance your business blog with an email newsletter, using a WordPress email plugin is indispensable. These plugins not only simplify content distribution but also offer insights into your target audience’s preferences, enabling you to optimize your content strategy effectively.

Discover the 15 best WordPress email plugins on the market from the list below, and choose the one that’s right for your needs and goals.

Download Now: Email Marketing Planning Template 

1. HubSpot WordPress Plugin

Best wordpress email plugins, HubSpot’s WP plugin email builder

The HubSpot WordPress Plugin offers a variety of features to help you collect leads and grow your customer base. In addition to allowing you to create forms and pop-ups with a simple drag-and-drop interface, HubSpot collects submissions from any form on your WordPress site and instantly adds those leads to your CRM, allowing you to start nurturing them into loyal customers right away.

The plugin features a live chat function, which allows you to start interacting with site visitors and potentially create leads from such talks. You may also use bots to answer simple inquiries from your website visitors, ensuring that you’re helping them even when your team is unavailable.

When someone fills out one of your pop-up forms, you can automate a simple kickback email to contact them and give them the stuff you promised. You can also upgrade to a paid version of Marketing Hub to begin emailing those contacts right away.

Best for: We recommend the HubSpot WordPress Plugin for anyone. Between forms, pop-ups, live chat, and a fully integrated CRM, there’s no better free email subscription plugin available for WordPress.

2. MailPoet

Best wordpress email plugins, MailPoet

MailPoet is one of the most popular free WordPress newsletter plugins. You can quickly import an existing list from your CRM or another marketing automation solution to manage your subscribers, or you can construct forms and add them to your site using widgets. Furthermore, the email editor’s drag-and-drop functionality allows you to easily design responsive emails that look fantastic on any device or email service.

MailPoet is free for those with fewer than 1,000 subscribers, but it grows more powerful as you upgrade. Premium customers, among other sophisticated capabilities, may observe which subscribers have opened your email and which links people are clicking on within your email.

Best for: Those looking for a popular, free, and adaptable WordPress email newsletter plugin can test MailPoet and play around with its subscriber management, email building, and automation capabilities. Those with smaller lists can also benefit from premium features for free.

3. Newsletter

Best wordpress email plugins, Newsletter

Newsletter is a WordPress email marketing tool that offers all-inclusive features. It lets you easily add subscription forms, create emails with a drag-and-drop builder, segment leads using multi-list targeting, and automate regular newsletters for consistent subscriber engagement. It provides built-in reporting for email performance insights and integrates with tools like Mailgun and Spark Post for optimized email strategies.

Best for: The Newsletter plugin is best for WordPress bloggers looking to automate their newsletters and track performance. It’s another popular, well-received option that’s worth trying out for free.

4. Brevo

best wordpress email plugins, Brevo

Brevo (formerly Sendinblue), a cloud-based digital marketing solution trusted by over 50,000 businesses worldwide, seamlessly integrates with WordPress through its dedicated plugin. This plugin enables you to efficiently create lead-capturing forms, manage subscriber lists, conduct email marketing campaigns, and assess campaign performance using detailed reports. The drag-and-drop email editor facilitates personalized engagement, and the free version allows for up to 300 daily emails.

Moreover, the Brevo WordPress plugin extends its utility to transactional emails. Leveraging the wp_mail function, you can effortlessly send transactional emails using Brevo’s Simple Mail Transfer Protocol (SMTP) service. This functionality proves invaluable for sending order confirmations and keeping customers informed about vital account changes. Elevate your WordPress capabilities by incorporating Brevo’s practical tools and enhancing communication efficiency.

Best for: WordPress business owners in need of a simple but inclusive email marketing plugin will enjoy Brevo for its tools, support, and integration with its other advanced marketing tools. You can get decent mileage from the plugin for free before reaching your send limit.

5. Sumo

best wordpress email plugins, Sumo

Sumo boasts an impressive 30,000 active WordPress installations, renowned for its versatile growth-focused tools. Beyond pop-ups, welcome emails, and automated drip campaigns, it equips you with additional resources for business expansion.

The plugin showcases a versatile “share” button, facilitating seamless content sharing across social platforms. Seamless integration with WooCommerce empowers you to generate discounts and exclusive offers, curbing abandoned carts and boosting order values.

Sumo takes it a step further with free customer support and personalized onboarding for all users, regardless of their subscription tier. Maximize plugin benefits with Sumo’s holistic support approach.

Best for: Sumo works great for ecommerce websites and WooCommerce that run regular email campaigns. New businesses will appreciate the generous free version, which allows up to 10,000 emails per month and unlimited subscribers.

6. Icegram Express

best wordpress email plugins, Icegram Express

Icegram Express, a user-friendly plugin, simplifies notifying subscribers about fresh blog content. Seamlessly incorporate a subscription box onto your site and receive instant notifications upon new sign-ups. Effortlessly alert your subscribers upon new post releases or curate bespoke newsletters to disseminate your content.

The plugin’s commitment to list health is evident, offering double opt-in functionality for targeted outreach. Safeguard against bot interference by integrating captchas into your subscription box. The tool’s utility extends to list cleanup and spam testing, ensuring optimal email list integrity.

Best for: Icegram Express is best for bloggers who want a simple plugin to notify readers when a new blog post is published, along with some simple metrics and a custom newsletter option.

7. Subscribe2

best wordpress email plugins, Subscribe2

Subscribe2, a versatile plugin, empowers communication with your blog subscribers. Effortlessly dispatch straightforward notifications upon new content or deliver periodic post digests, and tailor your emails by excluding specific post categories or individual posts.

The plugin supports both plain text and custom HTML email creation, accommodating your preferences. Enhance your capabilities by upgrading to its paid service, weMail, enabling direct email transmission to Mailchimp, AWeber, and other prominent email service providers.

Best for: Subscribe2 is another WordPress email plugin that’s ideal for bloggers who want to send email alerts to subscribers or to compile their most recent blog posts into a digest.

8. SendPress Newsletters

best wordpress email plugins, sendpress newsletters

SendPress Newsletters, an intuitive email newsletter plugin, streamlines communication effortlessly. Seamlessly import WordPress contacts and content, enabling swift creation of blog notification emails.

With SendPress, you gain access to an array of styling and editing tools, allowing for professional emails devoid of coding requirements. The AutoCron service ensures the consistent dispatch of scheduled emails by regularly monitoring your site.

However, be aware that advanced features like analytics, bounce handling, and campaign tracking via third-party platforms such as Google Analytics require an upgrade to the paid version.

Best for: SendPress provides a simple email automation subscription for small WordPress sites that want to grow their audiences.

9. OptinMonster

best wordpress email plugins, optinmonster

OptinMonster, a renowned and potent plugin, thrives in augmenting your WordPress email list and boosting subscribers through dynamic pop-ups and static forms. The plugin boasts a user-friendly drag-and-drop editor, enabling form creation from scratch or using ready-made templates.

OptinMonster stands apart due to its advanced targeting capabilities. Employing exit intent technology, it triggers pop-ups as users prepare to exit a page. Moreover, page-level targeting personalizes content offers according to visitor behavior and location on your site. Capitalize on this data by seamlessly integrating with OptinMonster’s diverse email service providers, facilitating tailored email campaigns.

Best for: Marketers who want to implement pop-ups in their marketing strategies (especially for exit intents), and implement advanced tracking on their forms and email campaigns to drive conversions.

10. Thrive Leads

best wordpress email plugins, thrive leads

Similar to OptinMonster, Thrive Leads is dedicated to rapid subscriber list expansion. This versatile tool boasts a wide range of pop-up styles, from full-screen overlays to multiple-choice forms, complemented by comprehensive targeting options.

Thrive Leads takes it a step further with A/B testing, enabling you to gauge the performance of varied designs or content offers. This invaluable feature empowers substantial conversion rate enhancements, enhancing the efficacy of your efforts.

Best for: Thrive Leads is a complete solution that assists online businesses in increasing subscriptions, increasing conversions, and targeting the appropriate people at the right time. If this describes you, give it a go. Also, keep in mind that Thrive Leads is primarily a form tool — email is only one component, and the plugin performs best when combined with another email tool.

11. WP Subscribe

Best WordPress email plugins, WP Subscribe

WP Subscribe, crafted by MyThemeShop, aligns with their hallmark of fast, reliable, SEO-friendly WordPress products. The plugin’s streamlined code guarantees rapid loading without site slowdowns.

Position your subscription form anywhere, assured of its responsiveness across screens. WP Subscribe seamlessly integrates with leading email service providers like AWeber and MailChimp, ensuring swift email list utilization. Enhance your strategy with WP Subscribe’s precision and performance focus.

Best for: Use WP Subscribe to build custom forms and grow your email list — for anything else, you’ll need to integrate with another email automation tool.

12. Ninja Forms

best wordpress email plugins, ninja forms

Ninja Forms dominates with over 800,000 WordPress installations, ranking among the top form plugins. It delivers anticipated email subscription form features and distinctive extras, notably a renowned builder tool enabling code-free professional form creation.

Counter spam effectively through diverse options, including Google’s reCAPTCHA. Facilitate seamless payments via PayPal Express, Stripe, and Elavon integrations, and instantly engage new leads by integrating with a host of prominent mailing list tools.

Best for: WordPress users who need a reliable form builder tool to grow their email subscriber list should put Ninja Forms on the list — it’s one of the leading options available, and it’s flexible enough that you can use it for other cases beyond email signups.

13. Email Template Customizer for WooCommerce

best wordpress email plugins, woocommerce email template customizer

Enhance WooCommerce with the Email Template Customizer plugin. Personalize email templates seamlessly with drag-and-drop ease, leveraging WooCommerce-specific elements like order and shipping details. Streamline transactional emails, order confirmations, and shipping notifications.

Upgrade to the paid version for advanced features: Suggest products, provide coupons, and send targeted emails based on specific order criteria. Tailor your WooCommerce emails efficiently with Email Template Customizer’s intuitive toolkit.

Best for: WooCommerce site owners should try Email Template Customizer for WooCommerce as a solution to build custom emails to customers.

14. WP Mail SMTP by WPForms

best wordpress email plugins, WP Mail SMTP

The creators of WPForms introduce WP Mail SMTP, an email-focused plugin targeting deliverability hurdles. By replacing PHPMailer with SMTP, it enhances email reliability. Boasting 3 million+ downloads, it elevates deliverability, avoiding spam folders and failures.

WP Mail SMTP authenticates emails to clients, smoothly integrating with reputable SMTP providers through a wp_mail() function reconfiguration. For the uninitiated, the plugin offers a guided setup and comprehensive documentation for seamless navigation. Overcome deliverability challenges with WP Mail SMTP’s strategic intervention.

Best for: WordPress marketers who are experiencing email deliverability issues may consider trying this plugin.

15. Icegram Engage

best wordpress email plugins, icegram engage

Icegram is a powerful plugin specifically designed to increase engagement, gather leads, and build relationships with your customers. It offers a plethora of features such as opt-in forms, notifications, pop-ups, welcome mats, and much more. With the help of the A/B testing feature you can optimize your campaigns for maximum conversions. Icegram also integrates with a wide range of email marketing services like MailChimp and AWeber to easily sync your leads from the website.

Best for: Marketers who want an all-in-one solution that is easy to set up and use, and that can help them engage with their customers, build relationships, and grow their email leads list. Icegram is a great choice for those looking to maximize their conversions on WordPress websites.

Upgrade your WordPress emails.

It is critical to select the plugin that works best for you. Whether you need a highly configurable plugin or one that just drives submissions so you can get your email newsletter off the ground, the options above are a wonderful place to start whenever you contemplate how to start building out your subscriber list.

Editor’s note: This post was originally published in November 2021 and has been updated for comprehensiveness.

New Call-to-action

The post The 15 Best WordPress Email Plugins in 2024 appeared first on ProdSens.live.

]]>
https://prodsens.live/2024/02/07/the-15-best-wordpress-email-plugins-in-2024/feed/ 0
How to Use the SUBTRACT Function in Excel https://prodsens.live/2024/02/07/how-to-use-the-subtract-function-in-excel/?utm_source=rss&utm_medium=rss&utm_campaign=how-to-use-the-subtract-function-in-excel https://prodsens.live/2024/02/07/how-to-use-the-subtract-function-in-excel/#respond Wed, 07 Feb 2024 12:20:29 +0000 https://prodsens.live/2024/02/07/how-to-use-the-subtract-function-in-excel/ how-to-use-the-subtract-function-in-excel

Excel is a powerful spreadsheet program from Microsoft that makes it easy to work with numbers and other…

The post How to Use the SUBTRACT Function in Excel appeared first on ProdSens.live.

]]>
how-to-use-the-subtract-function-in-excel

Excel is a powerful spreadsheet program from Microsoft that makes it easy to work with numbers and other values.

While Excel contains a lot of power, it’s also quite useful for simple addition, subtraction, multiplication, and division.

Download 10 Excel Templates for Marketers [Free Kit]

In fact, Excel’s simple formulas make it easy to add and subtract numbers and cell values without breaking out a calculator.

How to Use Subtract Function in Excel

Many of Excel’s most powerful capabilities come via the use of functions, which are a kind of predesigned formula.

For example, the SUM function automatically sums or totals a range of cells without you having to manually add each cell to the previous one. 

Unfortunately, there is no SUBTRACT function in Excel. That’s because subtracting is one of the easiest things you can do in a spreadsheet. 

I‘ve found that performing subtraction in Excel is as simple as entering a simple mathematical formula. Excel does the rest. 

The formula for subtracting one number from another starts with an equal sign and looks like this:

=value1 – value2

It doesn’t get much easier than that. You can subtract discrete values or the values contained in individual cells. 

For example, let’s say I want to put an aquarium in my home so I can enjoy tropical fish.

I made a spreadsheet of the different tasks I need to complete and how much I expect each purchase to cost. I then gather the receipts to note what I actually spent. We’ll use subtract to see if my expected costs match reality. 

Step 1: Type an equal sign in a cell.

You subtract numbers and cell values in Excel using a simple formula. In Excel, every formula starts with an equal sign, so position your cursor in the cell where you want to show the solution and enter the following:

=

subtract in excel, step 1

Step 2: Add the first cell address.

Position the cursor after the equal and either manually enter the first cell address or use your mouse to select the first cell. You should now see something like this:

=B2

subtract in excel, step 2

Step 3: Enter a minus sign.

Position the cursor after the first cell address and enter a minus sign, like this:

=B2-

Step 4: Add the second cell address.

Position the cursor after the minus sign and either manually enter the second cell address or use your mouse to select the second cell. You now have the following formula:

=B2-C2

subtract in excel, step 4

Step 5: Press enter to the solution.

Press enter to enter the formula, and the solution is displayed in the cell. After running the formula on every line in my sheet, I can see that I completed my aquarium with $236 to spare. 

subtract in excel, step 5

Tips for Subtracting in Excel

You’re not limited to subtracting just one cell from another. In my experience, I’ve found that Excel can perform many different types of subtraction.

For example, you can subtract entire rows and columns, as well as cell ranges. Here are three tips on how to get the most out of subtracting in Excel.

How to Subtract Multiple Cells

You’re not limited to simple subtraction in Excel. You can subtract multiple cells from a single cell by stringing together additional cell addresses with minus signs.

For example, to subtract cells C13 through C 18 from B12, use the formula:

=B12-C13-C14-C15-C16-C17-C18

subtract in excel, example

You could also write this as subtracting a range of cells from the first cell. In this instance, you’d use the range B2:B4 and enter this formula:

=B12-(C13:C18)

subtract in excel, example

Just enclose the range you’re subtracting within parentheses. 

How to Subtract Entire Columns

You may want to subtract all the values in one column from all the values in another column. This is easily done by copying the formula from a single cell to all the cells in the solution column.

Simply enter your subtraction formula into the first cell in a new column. Then, copy that formula to the other cells in the column by dragging the corner of the first cell down the column.

All the cells in subsequent rows will subtract the same two relative cells as in the first formula.

For example, if you copy the formula =D1-C1 downward through a column, the cells in each subsequent row would contain the formulas:

=B2-C2

=B3-C3

=B4-C4

And so on. 

subtract in excel, column

How to Subtract the Same Number From a Column of Numbers

Excel also lets you subtract the same number or cell value from all the cells in a column. You do this by locking the repeated number with dollar signs ($). 

Let’s say you want to subtract the value in a given cell from a range of cells. For our example, assume the cell you want to subtract is G1. 

You can’t just enter G1 and then copy the formula because Excel will change the referenced cell as you copy the formula.

Instead, you need to lock G1 into the formula by using dollar signs ($) in front of the row and column referenced by entering $G$1.

This tells Excel to always reference cell G1, whatever the other values in the formula. You end up with something like this:

=C2-$G$1

Pro tip: You can then copy that formula down an entire column, subtracting the fixed number from each cell in that column.

To learn even more about Excel, check out our article on How to Use Excel Like a Pro. This useful article contains 29 powerful tips, tricks, and shortcuts that will make Excel even more powerful. 

Getting Started

Excel includes powerful arithmetic capabilities, including the ability to subtract numbers and cell values. Excel makes simple subtraction as easy as writing numbers on a blackboard.

excel marketing templates

The post How to Use the SUBTRACT Function in Excel appeared first on ProdSens.live.

]]>
https://prodsens.live/2024/02/07/how-to-use-the-subtract-function-in-excel/feed/ 0
Improving Data Quality in ClickHouse Databases with Soda https://prodsens.live/2024/01/20/improving-data-quality-in-clickhouse-databases-with-soda/?utm_source=rss&utm_medium=rss&utm_campaign=improving-data-quality-in-clickhouse-databases-with-soda https://prodsens.live/2024/01/20/improving-data-quality-in-clickhouse-databases-with-soda/#respond Sat, 20 Jan 2024 02:24:16 +0000 https://prodsens.live/2024/01/20/improving-data-quality-in-clickhouse-databases-with-soda/ improving-data-quality-in-clickhouse-databases-with-soda

Introduction Data quality is the bedrock of any data-driven project, ensuring the integrity and reliability of information. Soda,…

The post Improving Data Quality in ClickHouse Databases with Soda appeared first on ProdSens.live.

]]>
improving-data-quality-in-clickhouse-databases-with-soda

Introduction

Data quality is the bedrock of any data-driven project, ensuring the integrity and reliability of information. Soda, a versatile tool catering to Data Engineers, Data Scientists, and Data Analysts, empowers users to conduct data quality tests precisely when and where they need to. This guide merges theoretical insights with practical examples from the soda-clickhouse project, showcasing how Soda can significantly enhance data quality in ClickHouse databases.

Soda Use Case Guides

1. Testing Data in a Pipeline

Integrate Soda seamlessly into your data pipeline to perform continuous data quality checks. Define checks using SodaCL, include scans at key pipeline stages, and monitor results for early issue detection, ensuring data quality at every step.

2. Testing Data Before Migration

Prioritize data integrity before migration by configuring Soda for both source and target databases. Leverage Soda’s reconciliation checks to verify data consistency and resolve any issues identified in pre-migration scans, ensuring a smooth transition.

3. Testing Data in CI/CD

Incorporate Soda into your CI/CD pipeline for automated data quality checks. Configure alerts for failures, seamlessly integrate with GitHub Actions, and maintain reliable data throughout the development lifecycle, fostering a culture of quality in your data-driven processes.

4. Self-Serve Soda

Empower your teams with self-serve capabilities using Soda. Facilitate easy access, encourage collaborative definition of quality checks, enable browser interface usage, and integrate with data catalogs for a holistic overview of dataset health, allowing teams to take ownership of their data quality.

Soda Cloud: Advanced Analytics and Collaboration

When it comes to reviewing scan results and investigating issues, Soda Cloud takes your data quality management to the next level. Here’s what you can do:

  • Review Scan Results:

    • Access visualized scan results not only in the command-line interface but also through the intuitive dashboard on Soda Cloud.
  • Set Alert Notifications:

    • Configure custom alert notifications to stay informed about any deviations or anomalies detected during scans. Proactively address potential data quality issues.
  • Track Trends Over Time:

    • Gain insights into the trends of your data quality metrics over time. Track improvements or deviations and make informed decisions about your data pipeline.
  • Integration with External Tools:

    • Seamlessly integrate Soda Cloud with your existing messaging, ticketing, and data cataloging tools. Collaborate more effectively by connecting with platforms like Slack, Jira, and Atlan.

Soda Cloud not only enhances the visibility of your data quality but also facilitates collaboration and advanced analytics, making it a powerful companion for managing and improving your data quality standards.

Project Samples: soda-clickhouse

Explore the soda-clickhouse project on GitHub, featuring two insightful samples:

  1. Sample_1: Data Quality in dim_customer Table

    • Dive into practical examples of performing quality checks on the dim_customer table within ClickHouse using Soda.
  2. Sample_2: Data Migration Validation

    • Ensure data integrity during migration from a MySQL to ClickHouse data source using reconciliation checks in Soda.

Conclusion

Implementing Soda for data quality assurance provides a comprehensive and effective approach. Whether you are testing data in a pipeline, before migration, in CI/CD, or enabling self-serve capabilities, Soda enhances the reliability and trustworthiness of your datasets. Explore the soda-clickhouse project, experiment with the provided samples, and leverage Soda’s capabilities to elevate your data quality standards and foster a data-driven culture. Elevate your data quality standards with Soda – making data reliability an integral part of your data journey.

The post Improving Data Quality in ClickHouse Databases with Soda appeared first on ProdSens.live.

]]>
https://prodsens.live/2024/01/20/improving-data-quality-in-clickhouse-databases-with-soda/feed/ 0
I built NextJS starters directory in 54 minutes https://prodsens.live/2023/12/06/i-built-nextjs-starters-directory-in-54-minutes/?utm_source=rss&utm_medium=rss&utm_campaign=i-built-nextjs-starters-directory-in-54-minutes https://prodsens.live/2023/12/06/i-built-nextjs-starters-directory-in-54-minutes/#respond Wed, 06 Dec 2023 00:25:02 +0000 https://prodsens.live/2023/12/06/i-built-nextjs-starters-directory-in-54-minutes/ i-built-nextjs-starters-directory-in-54-minutes

Hey builders. I’ve built & launched a directory from 0→1 in 54 minutes. A real experiment with a…

The post I built NextJS starters directory in 54 minutes appeared first on ProdSens.live.

]]>
i-built-nextjs-starters-directory-in-54-minutes

Hey builders.

I’ve built & launched a directory from 0→1 in 54 minutes.
A real experiment with a happy end!
7 steps.

→ Idea.
NextJS starter kits and boilerplates are super hot these days. It was as hot as gpts or AI back in the day. So I saw the trend.

→ Name & Domain.
I went to Google and searched for everything related to this to find a keyword that got nothing serious on the top. Then I looked at the Google searches for this keyword and picked the one with 10k searches but low competition and it was available on Godaddy for $10.

→ Directory and text.
I went to unicornplatform, picked a directory template, and cloned it.
I asked AI to edit to next based on the project name, it just made it all well from the first try.

→ Images, logo, favicon, video.
I asked ChatGPT Vision to generate this. It did a good job. Then I went to runwayml to edit the generated images with prompts and the gif for the tweet.
Took me about 10 minutes to make it beautiful.

→ Content.
I went to DevHunt and PH and found winners. Added 4. Just to start with.

→ New content.
I added a form so people can submit their NextJS starters, so that I can start to fill up the list.

→ I’ve wrote this tweet, and I’m about to hit “Post” btn

Submit your starter kits, in case this goes viral, those who submit first will be on the top of the list
→→→ nextjsstarter.com

My next steps
→ turn on seobotai
to win the organic SEO traffic
→ list it everywhere using listingbott
→ launch in on PH and DevHunt

my original post

// Detect dark theme
var iframe = document.getElementById(‘tweet-1732167423296405617-658’);
if (document.body.className.includes(‘dark-theme’)) {
iframe.src = “https://platform.twitter.com/embed/Tweet.html?id=1732167423296405617&theme=dark”
}

The post I built NextJS starters directory in 54 minutes appeared first on ProdSens.live.

]]>
https://prodsens.live/2023/12/06/i-built-nextjs-starters-directory-in-54-minutes/feed/ 0
Validating forms in React Apps with Zod https://prodsens.live/2023/11/30/validating-forms-in-react-apps-with-zod/?utm_source=rss&utm_medium=rss&utm_campaign=validating-forms-in-react-apps-with-zod https://prodsens.live/2023/11/30/validating-forms-in-react-apps-with-zod/#respond Thu, 30 Nov 2023 23:25:43 +0000 https://prodsens.live/2023/11/30/validating-forms-in-react-apps-with-zod/ validating-forms-in-react-apps-with-zod

After a lot of attempts, and experimenting different versions of it, I’ve come with what I’d say is…

The post Validating forms in React Apps with Zod appeared first on ProdSens.live.

]]>
validating-forms-in-react-apps-with-zod

After a lot of attempts, and experimenting different versions of it, I’ve come with what I’d say is the best way to validate forms. In this post I’ll try to explain, step by step, how I do it. I hope this helps you in any way, as others helped me with their posts here.

So, let’s go!

Starting setup

Lets start with a simple form, with some of the most requested data.

form draft

// component Form
export function Form() {
  return (
    <form className="form">
      <label htmlFor="">Name</label>
      <input type="text" />

      <label htmlFor="">Email</label>
      <input type="email" />

      <label htmlFor="">Password</label>
      <input type="Password" />

      <label htmlFor="">Number</label>
      <input type="number" />

            <button type="submit" className="button">
        Enviar
      </button>
    </form>
  );
}

// main page
import './App.css';
import { Form } from './components/Form';

function App() {
  return (
    <div className="container">
      <Form />
    </div>
  );
}

export default App;

Installing React Hook Form

$ npm install react-hook-form

Installing Zod

$ npm install zod

Adapting Form component to React Hook Form

To use React Hook Form, we will adequate our form according to the basic example usage, from the documentation:

  • import register, handleSubmit and errors from useForm
  • register must be inserted on every input, with its respective name
  • call handleSubmit, from React Hook Form, at the ‘onSubmit’ method of the form, receiving the ‘submitForm’, created by us. The submitForm function is where you will decide how to submit your data. In this example, we will only console the form data.
  • if the input is not validated at submit, an error will be presented at ‘errors’, to the respective not validated input.
import { useForm } from 'react-hook-form';

interface Inputs {
  name: string;
  email: string;
  password: string;
  number: number;
}

export function Form() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<Inputs>();

  function submitForm() {
    console.log('submit');
  }

  return (
    <form className="form" onSubmit={handleSubmit(submitForm)}>
      <label htmlFor="">Name</label>
      <input type="text" {...register('name')} />

      {errors?.name && 'erro'}

      <label htmlFor="">Email</label>
      <input type="email" {...register('email', { required: true })} />
      {errors?.email && 'erro'}

      <label htmlFor="">Password</label>
      <input type="Password" {...register('password')} />

      <label htmlFor="">Number</label>
      <input type="number" {...register('number')} />

      <button type="submit" className="button">
        Enviar
      </button>
    </form>
  );
}

Using Zod

Now, we will add Zod validation to the form. First, we need to install it, along with @hookform/resolvers, to correctly use Zod with React Hook Form:

Installing Zod

$ npm install zod
$ npm install @hookform/resolvers

Creating the validation Schema

Now, we will create an object schema, and infer its type:

import { z } from 'zod';
import { zodResolver } from "@hookform/resolvers/zod";

const validationSchema = z.object({
  name: z.string().min(1),
  email: z.string().min(1).email(),
  password: z.string().min(1),
  phone: z.string().min(1),
});

type SchemaProps = z.infer<typeof validationSchema>;

We also need to change our useForm, passing its resolver:

const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<SchemaProps>({
    resolver: zodResolver(validationSchema)
  });

Don’t forget to put the error messages in the form!

// form should look something like this
<form className="form" onSubmit={handleSubmit(submitForm)}>
      <div>
        <label htmlFor="">Namelabel>
        {errors?.name && <span>{errors.name.message}span>}
      div>
      <input type="text" {...register('name')} />

      <div>
        <label htmlFor="">Emaillabel>
        {errors?.email && <span>{errors.email.message}span>}
      div>
      <input type="email" {...register('email')} />

      <div>
        <label htmlFor="">Passwordlabel>
        {errors?.password && <span>{errors.password.message}span>}
      div>
      <input type="Password" {...register('password')} />

      <div>
        <label htmlFor="">Phone Numberlabel>
        {errors?.phone && <span>{errors.phone.message}span>}
      div>
      <input type="string" {...register('phone')} />

      <button type="submit" className="button">
        Enviar
      button>
    form>

The form, with active errors, should look like this:

active errors form

Customizing

Now, let’s customize our validation. We will:

  • insert custom error messages to each validation, of each property
  • insert strong password validation (min 8 characters, one uppercase, one lowercase, one number and one special character)
  • insert phone number validation (brazilian phone number)
// phone validation (Brazil)
const phoneValidation = new RegExp(
  /^(?:(?:+|00)?(55)s?)?(?:(?([1-9][0-9]))?s?)?(?:((?:9d|[2-9])d{3})-?(d{4}))$/
);

// Minimum 8 characters, at least one uppercase letter, one lowercase letter, one number and one special character
const passwordValidation = new RegExp(
  /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/
);

const validationSchema = z.object({
  name: z.string().min(1, { message: 'Must have at least 1 character' }),
  email: z
    .string()
    .min(1, { message: 'Must have at least 1 character' })
    .email({
      message: 'Must be a valid email',
    }),
  password: z
    .string()
    .min(1, { message: 'Must have at least 1 character' })
    .regex(passwordValidation, {
      message: 'Your password is not valid',
    }),
  phone: z
    .string()
    .min(1, { message: 'Must have at least 1 character' })
    .regex(phoneValidation, { message: 'invalid phone' }),
});

For phone and password validations, we use the .regex, calling our validation, and passing the error message.

To sum up, this is the entire code of the component:

import { z } from 'zod';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';

const phoneValidation = new RegExp(
  /^(?:(?:+|00)?(55)s?)?(?:(?([1-9][0-9]))?s?)?(?:((?:9d|[2-9])d{3})-?(d{4}))$/
);

const passwordValidation = new RegExp(
  /^(?=.*[a-z])(?=.*[A-Z])(?=.*d)(?=.*[@$!%*?&])[A-Za-zd@$!%*?&]{8,}$/
);

const validationSchema = z.object({
  name: z.string().min(1, { message: 'Must have at least 1 character' }),
  email: z
    .string()
    .min(1, { message: 'Must have at least 1 character' })
    .email({
      message: 'Must be a valid email',
    }),
  password: z
    .string()
    .min(1, { message: 'Must have at least 1 character' })
    .regex(passwordValidation, {
      message: 'Your password is not valid',
    }),
  phone: z
    .string()
    .min(1, { message: 'Must have at least 1 character' })
    .regex(phoneValidation, { message: 'invalid phone' }),
});

type SchemaProps = z.infer<typeof validationSchema>;

export function Form() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<SchemaProps>({
    resolver: zodResolver(validationSchema),
  });

  function submitForm() {
    console.log('submit');
  }

  return (
    <form className="form" onSubmit={handleSubmit(submitForm)}>
      <div>
        <label htmlFor="">Namelabel>
        {errors?.name && <span>{errors.name.message}span>}
      div>
      <input type="text" {...register('name')} />

      <div>
        <label htmlFor="">Emaillabel>
        {errors?.email && <span>{errors.email.message}span>}
      div>
      <input type="email" {...register('email')} />

      <div>
        <label htmlFor="">Passwordlabel>
        {errors?.password && <span>{errors.password.message}span>}
      div>
      <input type="Password" {...register('password')} />

      <div>
        <label htmlFor="">Phone numberlabel>
        {errors?.phone && <span>{errors.phone.message}span>}
      div>
      <input type="string" {...register('phone')} />

      <button type="submit" className="button">
        Enviar
      button>
    form>
  );
}

form

That’s it guys! I hope you enjoyed reading it, and that it helped you understand a little about how it works.

Also, if you have any advices or comments on this, please leave a comment!

The post Validating forms in React Apps with Zod appeared first on ProdSens.live.

]]>
https://prodsens.live/2023/11/30/validating-forms-in-react-apps-with-zod/feed/ 0
Partitioned S3 Bucket from DynamoDB https://prodsens.live/2023/11/18/partitioned-s3-bucket-from-dynamodb/?utm_source=rss&utm_medium=rss&utm_campaign=partitioned-s3-bucket-from-dynamodb https://prodsens.live/2023/11/18/partitioned-s3-bucket-from-dynamodb/#respond Sat, 18 Nov 2023 01:25:05 +0000 https://prodsens.live/2023/11/18/partitioned-s3-bucket-from-dynamodb/ partitioned-s3-bucket-from-dynamodb

I’ve been working recently with some data that doesn’t naturally fit into my AWS HealthLake datastore. I have…

The post Partitioned S3 Bucket from DynamoDB appeared first on ProdSens.live.

]]>
partitioned-s3-bucket-from-dynamodb

I’ve been working recently with some data that doesn’t naturally fit into my AWS HealthLake datastore. I have some additional information captured in a DynamoDB table that would be useful to blend with HealthLake but on its own is not an FHIR resource. I pondered on this for a while and came up with the idea of piping DynamoDB stream changes to S3 so that I could then pick up with AWS Glue. In this article, I want to show you an approach to building a partitioned S3 bucket from DynamoDB. Refining that further with Glue jobs, tables and crawlers will come later.

Architecture

What I like about this approach is that it’s Serverless. Nothing to manage and nothing to provision ahead of time. Everything in this stack expands or collapses based on the need.

In addition, it builds upon some of the topics I’ve covered on the blog before, so there are plenty of examples and repos to extend. Most recently with this DynamoDB and EventBridge Pipes Stream example.

Partitioned S3 Bucket from DyanamoDB

Setting up the Problem

Back to the original need for this pattern. Sometimes you will have data stored in DynamoDB that you will want to report on. And as much as I love DDB, it’s not what I’m choosing to handle most reporting workloads. Second, a very reliable and scalable way to organize data before it is refined into useful information is to leverage a Data Lake. And lastly, before you can start refining that data, you need it to land somewhere and preferably organized in some format.

For the balance of the article, I’m going to walk through some TypeScript CDK code and Golang to build this reliable data staging pipeline.

Partitioned S3 bucket from DynamoDB

DynamoDB Table

The TableConstruct builds a simple table with PAY_PER_REQUEST pricing, a customer-managed KMS and a single PARTITION_KEY.

this._table = new Table(this, id, {
    billingMode: BillingMode.PAY_PER_REQUEST,
    removalPolicy: RemovalPolicy.DESTROY,
    partitionKey: { name: "id", type: AttributeType.STRING },
    tableName: `AnalyticsTable`,
    encryption: TableEncryption.CUSTOMER_MANAGED,
    encryptionKey: props.key,
    stream: StreamViewType.NEW_AND_OLD_IMAGES,
});

Below are a couple of sample records that I’m going to be working with.

{
  "valueOne": 123,
  "siteId": "2",
  "createdAtTime": 1700076551926,
  "valueTwo": 6789,
  "id": "123",
  "name": "Name one"
}

{
  "valueOne": 782,
  "siteId": "1",
  "createdAtTime": 1700076551318,
  "valueTwo": 152,
  "id": "456",
  "name": "Name one"
}

Shaping with EventBridge Pipes

Shaping the output of a DynamodDB stream is straightforward when using EventBridge Pipes. I wrote an extensive article here about how to do that, so I won’t go into too much detail but do want to highlight the approach.

Defining the Pipe

Below is the TypeScript code that builds the pipe. With some of the other targets such as EventBridge or SQS, there are target parameters to specify. In the case of using Firehose that isn’t required. In replacement of that, I’m just inlining the input template for the target itself. That input template is present in all of the other specific targets as well and it gives me the chance to shape the DDB stream input into my format.

const pipe = new CfnPipe(scope, "Pipe", {
    name: "Ddb-Stream-Firehose-Pipe",
    roleArn: pipeRole.roleArn,
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    source: props.table.tableStreamArn!,
    // enrichment: props.enrichmentFunction.functionArn,
    target: props.firehose.attrArn,
    targetParameters: {
        inputTemplate: '{ "createdAtTime": "<$.dynamodb.NewImage.createdAtTime.N>", "siteId": "<$.dynamodb.NewImage.siteId.S>", "id": "<$.dynamodb.NewImage.id.S>", "name": "<$.dynamodb.NewImage.name.S>", "valueOne": "<$.dynamodb.NewImage.valueOne.N>", "valueTwo": "<$.dynamodb.NewImage.valueTwo.N>" }'
    },
    sourceParameters: this.sourceParameters(),

Also, don’t skip over the IAM permissions the pipe will need for issuing a Direct PUT into Kinesis Firehose. I could have been lazy and used kms:* or firehose:* but that isn’t very secure 🙂

return new PolicyDocument({
    statements: [
        new PolicyStatement({
            sid: "KMSPolicy",
            actions: [
                "kms:Decrypt",
                "kms:DescribeKey",
                "kms:Encrypt",
                "kms:GenerateDataKey*",
                "kms:ReEncrypt*",
            ],
            effect: Effect.ALLOW,
            resources: [props.key.keyArn],
        }),
        new PolicyStatement({
            sid: "FirehosePolicy",
            actions: [
                "firehose:DeleteDeliveryStream",
                "firehose:PutRecord",
                "firehose:PutRecordBatch",
                "firehose:UpdateDestination",
            ],
            effect: Effect.ALLOW,
            resources: [props.firehose.attrArn],
        }),
    ],
});

The Stream

In all transparency, I don’t use Firehose that often so I was excited to leverage it for building a partitioned S3 bucket from DynamoDB. I LOVE Kinesis in general and make use of Data Streams frequently but just don’t use Firehose much.

The main thing to understand about Firehose is that it’s a little like Pipes in that you have opportunities to shape and transform data as it flows through the system. You also have a few ways to ingest data and for this example, I’m going to make use of the generic Direct PUT option.

Since I haven’t done an article on Firehose before, I want to break down this CDK code a little bit, specifically the Props that set up the stream. The construct I’ll be leveraging is an L2 defined as CfnDeliveryStream. Documentation

Top-level properties give me the option to name the stream and choose the stream type. Remember above I mentioned Direct PUT and that’s because the source of EB Pipes is not a native integration. Which is why the Direct PUT option exists.

    deliveryStreamName: "analytics",
    deliveryStreamType: 'DirectPut',

The encryption configuration should seem pretty obvious. I’m leveraging the shared KMS Key I built in the stack. And then for the stream, specifying that it’s a CUSTOMER_MANAGED_CMK

deliveryStreamEncryptionConfigurationInput: {
    keyArn: props.key.keyArn,
    keyType: "CUSTOMER_MANAGED_CMK",
},

The output is where this gets fun. Building a partitioned S3 bucket is natively supported in Firehose. Quick aside, why does partitioning matter? A couple of key things.

  • Data organization
  • Data query performance

The extendedS3DestinationConfiguration can be a little long to build, but let me highlight some key pieces.

  • bufferingHints: The right interval and size take a little bit of art and science. For small samples of data, it doesn’t matter much, but performance can be impacted or improved by tweaking these.
  • roleArn: In the repository, you’ll see the specific permissions you need, but the role matters.
  • prefix: The bucket prefixing that’ll take place in S3. There are a few options to leverage, but in my example, I’m picking up these dynamic partitions from my Lambda. I’m structuring it like this site=1/year=2023/month=11/day=17/minute=32/dynamicPartitioningConfiguration: to support this partitioning, I need to enable dynamic partitioning.
  • processingConfiguration: Firehose supports in-line (jQ) based processing or you can use a Lambda function. In most cases, I’d like to use jQ, but for this example, I went with a Lambda
extendedS3DestinationConfiguration: {
    bucketArn: props.bucket.bucketArn,
    bufferingHints: {
        intervalInSeconds: 60,
        sizeInMBs: 128
    },
    encryptionConfiguration: {
        kmsEncryptionConfig: {
            awskmsKeyArn: props.key.keyArn
        }
    },
    roleArn: role.roleArn,
    prefix: 'data/siteId=!{partitionKeyFromLambda:siteId}/year=!{partitionKeyFromLambda:year}/month=!{partitionKeyFromLambda:month}/day=!{partitionKeyFromLambda:day}/minute=!{partitionKeyFromLambda:minute}/',
    errorOutputPrefix: 'errors/',
    dynamicPartitioningConfiguration: {
        enabled: true,
    },
    processingConfiguration: {
        enabled: true,
        processors: [{
            type: "Lambda",
            parameters: [
                {
                    parameterName: "LambdaArn",
                    parameterValue: props.transformation.functionArn
                },
            ]
        }]
    },
}

The Stream Lambda

As you can imagine, there isn’t a lot to the transformation Lambda code. I do want to showcase the structs that I’m working with that I hadn’t used before.

The signature of the handler is as follows:

func handler(ctx context.Context, firehose events.KinesisFirehoseEvent) (events.KinesisFirehoseResponse, error)

The best part of working with the events.KinesisFirehoseEvent is that it contains all of the records that the stream is holding in its buffer for processing. Then when packaging up my return payload, I can flag the records as success or failure so that I’m not dealing with any kinds of fractional failures and Poison Pill Messages.

err := json.Unmarshal(r.Data, &recordData)
if err != nil {
    log.WithFields(log.Fields{
        "err":      err,
        "recordID": r.RecordID,
    }).Error("Error unmarshalling the record")
    transformedRecord.Result = "ProcessingFailed"
    response.Records = append(response.Records, transformedRecord)
    continue
}

Additionally, I can build the dynamic partitions that I’ve shown as part of the bucket prefix.

partitionKeys["siteId"] = recordData.SiteId
partitionKeys["year"] = strconv.Itoa(recordData.CreatedAtTime.Year())
partitionKeys["month"] = strconv.Itoa(int(recordData.CreatedAtTime.Month()))
partitionKeys["day"] = strconv.Itoa(recordData.CreatedAtTime.Day())
partitionKeys["hour"] = strconv.Itoa(recordData.CreatedAtTime.Hour())
partitionKeys["minute"] = strconv.Itoa(recordData.CreatedAtTime.Minute())

Partitioned S3 Bucket

Since the example repository is using CDK, you can follow the directions in the README to install dependencies. Once you have all those configured, run.

cdk deploy

Your AWS Account should have the following resources configured.

  • S3 Bucket
  • DynamoDB Table
    • Configured for streams
  • EventBridge Pipe
    • Filtering rule
    • Target transformation
  • Kinesis Firehose
    • Direct PUT integration
    • Transformation enabled using a Lambda
  • KMS Key for encryption throughout
  • Various IAM policies for the services

Let’s take a small tour.

Example Table

Here is the configured stream.

Table Stream

EventBridge Pipe

Overview of the components.

EventBridge Pipe

Transform and target.

Pipe Transform

Kinesis Firehose

The configured Firehose stream

Kinesis Firehose

Partioned S3 Bucket from DynamoDB

And to wrap it all up, the partitioned S3 bucket populated from the DynamoDB source.

S3 Bucket

Wrap Up

Ultimately this is just part of a bigger solution that should include Glue Jobs, Tables and Crawlers plus Athena to power a more robust result. However, you can’t have analytics with preparing the data and step 1 is to acquire and organize it I hope you’ve seen a way to achieve this above. I would encourage you not to be afraid of some of these concepts as there are many ways to accomplish the above. Big data architecture and problem-solving are vast and have many paths to success. Start with what you are comfortable with and build from there. And ask questions along the way.

As with most of my articles, here is the sample repository. Feel free to clone it and adapt it to your needs. And when you are done, just run:

cdk destroy

Thanks for reading and happy building!

The post Partitioned S3 Bucket from DynamoDB appeared first on ProdSens.live.

]]>
https://prodsens.live/2023/11/18/partitioned-s3-bucket-from-dynamodb/feed/ 0
The Magic of Interfaces in Go https://prodsens.live/2023/10/23/the-magic-of-interfaces-in-go/?utm_source=rss&utm_medium=rss&utm_campaign=the-magic-of-interfaces-in-go https://prodsens.live/2023/10/23/the-magic-of-interfaces-in-go/#respond Mon, 23 Oct 2023 03:25:14 +0000 https://prodsens.live/2023/10/23/the-magic-of-interfaces-in-go/ the-magic-of-interfaces-in-go

Introduction DRY, or Don’t Repeat Yourself, is one of the most well-known software development principles. Many engineers will…

The post The Magic of Interfaces in Go appeared first on ProdSens.live.

]]>
the-magic-of-interfaces-in-go

Introduction

DRY, or Don’t Repeat Yourself, is one of the most well-known software development principles. Many engineers will go to great lengths to achieve this laudable goal, so a successful programming language must be designed with this in mind. Interfaces are just one of the tools that programming languages implement to enable code reuse.

Although there are countless differences in the way programming languages implement interfaces, they all define a contract for interaction between software components. Differentiating itself from the typical object-oriented implementation, the Go programming language implements interfaces in a way that aims to reduce complexity, encourage composition, and enable flexible use of the types.

Implicit Interfaces

The most impactful difference between Go’s interfaces and those from object-oriented languages is that Go’s interfaces work by implicit implementation. Rather than requiring a type to explicitly declare that it implements an interface, Go determines that a type satisfies an interface as long as it implements all of the required method signatures. The different types and the interface they implement are only coupled by the code using them, rather than always being linked together.

This difference offers a few key benefits:

  • Reduce complexity and coupling by limiting hierarchical inheritance of interfaces
  • Simplify types that implement multiple interfaces
  • Enables you to add interfaces later on when they become necessary instead of designing entire applications around them
  • Interfaces can be created for types in different packages

This last benefit is the most interesting and unique. The ability to define an interface based on external types leads to a few more specific advantages:

  • Client code can define how it will use types rather than relying on library code to tell it how types must be used
  • Create polymorphic relationships with types that you do not own or cannot change, which allows you to use them more flexibly
  • Solve import cycle issues by changing the location of interface definitions
  • Create mocks of imported types to make your code more testable

No Inheritance

By excluding inheritance, Go reduces the complexity that can occur from a deep hierarchical structure. When programs are designed around a base set of classes or interfaces, any simple changes to those base structures requires a significant refactor.

The alternative practice of composition leads to reduced complexity and more readable code. Composition relies on splitting up functionality among different types, and using them together, instead of re-defining the functionality of types through inheritance. Now you are able to re-use these individual components elsewhere, add more functionality with new components, and easily refactor or remove exiting ones.

Instead of being concerned about what type something is, your code just needs to known about what that type can do, and luckily the interface informs it.

Use Case: Polymorphism

Polymorphism is perhaps the entire reason behind the existence of interfaces. This common practice is one of the most effective and easy-to-use methods of code reuse. Since an interface defines a strict contract for how types are used, these different types can be used interchangeably; this is polymorphism.

A very common and useful scenario for this is having a flexible storage backend for your program: use Postgres in production, SQLite when running locally, and mocks when testing (or skip the database mocks, but that’s a topic for another day).

type StorageClient interface {
    GetValue(id string) (string, error)
}

func NewStorageClient(clientType string) (StorageClient, error) {
    switch clientType {
        case "sqlite":
            return sqlite.NewClient()
        case "postgres":
            return postgres.NewClient()
        default:
            return nil, fmt.Errorf("invalid client type: %s", clientType)
    }
}

This implementation allows you to easily use the StorageClient interface throughout the program without concern for the data storage layer behind it.

Use Case: Testing and Mocks

You can take advantage of the implicit nature of interfaces by defining an interface for the functions you use from an external library. For example, you are assigned a task to implement a function that fetches recent rain data, in inches, from a weather data API. The made-up weather provider publishes Go package called weather, which provides a Client struct with various weather-related methods returning data in metric units:

func GetRainInches(since time.Duration, client weather.Client) (float32, error) {
    rainMM, err := client.GetRain(since)
    if err != nil {
        return 0, fmt.Errorf("error getting data from API: %w", err)
    }

    return rainMM / 2.54, nil
} 

How will you unit test this code? Since Go has implicit interfaces, you can create your own interface that just defines the methods that you need from the library. Now, if your function expects this interface instead, you can create your own mocks. Since you currently just need the GetRain method, this is really simple:

type WeatherClient interface {
    GetRain(time.Duration) (float32, error)
}

func GetRainInches(since time.Duration, client WeatherClient) (float32, error) {
    rainMM, err := client.GetRain(since)
    if err != nil {
        return 0, fmt.Errorf("error getting data from API: %w", err)
    }

    return rainMM / 2.54, nil
}

Then, your test file might contain a new struct that also implements the interface:

type MockWeatherClient struct {
    expectedErr error
    expectedMM  float32
}

func (c MockWeatherClient) GetRain(time.Duration) (float32, error) {
    return c.expectedMM, c.expectedErr
}

After this simple refactor, you do not depend on external libraries to provide interfaces that make your own code testable! You have the additional side-effect of being one step closer to allowing your program to use different weather APIs generically.

Conclusion and Warnings

While interfaces in Go were designed with considerations for simplicity and avoiding some of the common pitfalls of object-oriented patterns, there are still some things to be aware of.

It may be tempting to define interfaces for everything with the hopes that you can create a more generic and flexible program. Remember that one of implicit interfaces is that you can easily create a new interface when you need it without making changes to any existing types, so there is no benefit to creating interfaces early in the process. Additionally, since types do not explicitly declare which interfaces they implement, it may be hard to tell which types are actually being used by your program when you have superfluous interfaces.

While there are always tradeoffs and no perfect solutions, I have found Go’s version of interfaces to be incredibly flexible, intuitive, and useful. I have been able to create more flexible programs and improve testability all while minimizing complexity.

The post The Magic of Interfaces in Go appeared first on ProdSens.live.

]]>
https://prodsens.live/2023/10/23/the-magic-of-interfaces-in-go/feed/ 0
Essential HTML Tags: Best Practices Breakdown https://prodsens.live/2023/08/23/essential-html-tags-best-practices-breakdown/?utm_source=rss&utm_medium=rss&utm_campaign=essential-html-tags-best-practices-breakdown https://prodsens.live/2023/08/23/essential-html-tags-best-practices-breakdown/#respond Wed, 23 Aug 2023 13:25:22 +0000 https://prodsens.live/2023/08/23/essential-html-tags-best-practices-breakdown/ essential-html-tags:-best-practices-breakdown

Essential HTML Tags: Best Practices Breakdown Introduction If you’re just starting out in the exciting world of frontend…

The post Essential HTML Tags: Best Practices Breakdown appeared first on ProdSens.live.

]]>
essential-html-tags:-best-practices-breakdown

Essential HTML Tags: Best Practices Breakdown

Introduction

If you’re just starting out in the exciting world of frontend development, you’re in for a treat.

Knowing your way around HTML is like having a hidden key to creating attractive websites in this digital age.

Whether you want to impress potential employers or simply want to build your own personal web space, learning these important HTML tags can set you up for success.

So, let’s dive in!

Setting the Stage: HTML at a Glance

So, what exactly is this HTML thing that everyone is talking about?

Consider it the skeleton of your web pages, the structure that allows your content to come to life. HTML, which stands for Hypertext Markup Language, may sound a little complicated, but trust me when I say it’s your ticket to making web magic.

Headings: Your Content’s Blueprint

Let’s start with the headings. These are the blueprints for your content.

These tags provide structure and hierarchy to your content, ranging from the prominent H1 (the main heading) to the less visible H6 (you guessed it, the smallest heading).

Not only do they make your page appear nice, but they also help search engines find your site.

Example:

Welcome to My Awesome Website

Paragraphs: Words Matter, Style Matters More

Following that, we have paragraphs. This is a widely used tag and believe me when I say that appropriately employing the

tag is critical for retaining readability.

Nobody likes a wall of text, do they? Whether you’re writing a blog post or an about me page, use

tags to make your information easier to read.

Example:

Are you ready to dive into the exciting world of web development? Whether you're a complete beginner or already have some coding experience, learning HTML is the first step towards creating stunning websites.

Consider online pages without links – a maze of isolation, right? That’s when the tag comes in handy!

You may construct hyperlinks that take your visitors to other pages, websites, or even cat videos with just a few lines of code. For an accessible touch, add descriptive text within the element using the href attribute.

Example:

Images: Eye Candy for Your Site

Let’s move on to the visuals! The tag is your ticket to include images into your site design.

But wait, there’s more: the alt attribute is your way of describing the image to people who can’t see it. Plus, search engines adore alt text, so it’s a win-win situation.

Example:

 src="image.jpg" alt="A beautiful sunset over the ocean">

Lists: Lists Make Life Easier

Lists aren’t the most glamorous aspect of web design, but boy, are they useful!

The

    and

      tags (unordered and ordered lists, respectively) will be your new best friends, whether you’re assembling your favourite coding resources or describing the steps of a recipe. And what about those

    1. tags? They’re like VIP passes to every thing on your list.

      Example:

      1. HTML
      2. CSS
      3. JavaScript
      4. React
      5. Angular
      6. Vue

      Forms: Let’s Get Interactive

      Forms, the interactive web development playground. From contact forms to login pages, the

      tag opens up a world of user engagement.

      Include tags for text fields, checkboxes, radio buttons, and other controls. It’s similar to starting a digital interaction with your customers. Isn’t that amazing?

      Example:

       action="signup.php" method="post">
         for="username">Username:
         type="text" id="username" name="username" required>
      for="email">Email: type="email" id="email" name="email" required>
      for="password">Password: type="password" id="password" name="password" required>
      type="submit" value="Sign Up">

      Semantic Tags: Adding Meaning to Your Markup

      Let’s get a little more creative with some semantic HTML5 tags. These gems, like

      ,