{"componentChunkName":"component---src-templates-blog-list-jsx","path":"/blog/12/","result":{"data":{"prismic":{"allFeaturedblogs":{"edges":[{"node":{"featured_blogs_enabled":true,"heading":[{"type":"paragraph","text":"Featured posts","spans":[]}],"featured_blog_1":{"__typename":"PRISMIC_Blog","_linkType":"Link.document","blog_header_image":{"dimensions":{"width":790,"height":395},"alt":null,"copyright":null,"url":"https://images.prismic.io/www-static/6d8d81b1-971a-4313-b033-b4e125cb14a0_MondoDB-blog-header-790x395.PNG?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Introducing DigitalOcean Managed MongoDB – a fully managed, database as a service for modern apps","spans":[]}],"blog_post_date":"2021-06-29","blog_post_content":[{"type":"paragraph","text":"MongoDB is one of the most popular databases, and it’s ideal for apps that evolve rapidly and need to handle huge volumes of data and traffic. It offers advantages like flexible document schemas, code-native data access, change-friendly design, and easy horizontal scale-out.","spans":[{"start":22,"end":44,"type":"hyperlink","data":{"link_type":"Web","url":"https://db-engines.com/en/ranking","target":"_blank"}}]},{"type":"paragraph","text":"However, building and maintaining MongoDB clusters from the ground up can be a huge undertaking. Developers often complain that they have to spend their valuable time and resources on database management. Well, we’ve been listening and have some great news: accessing and managing MongoDB on DigitalOcean just got a lot simpler!","spans":[]},{"type":"paragraph","text":"We are excited to announce that DigitalOcean Managed MongoDB is now in General Availability. Managed MongoDB is a fully managed, database as a service (DBaaS) offering from DigitalOcean, built in partnership with and certified by MongoDB Inc. It provides you all the technical capabilities that make MongoDB so beloved in the developer community. Together we have ensured that you will get access to all the latest releases of the MongoDB document database as they become available.","spans":[{"start":32,"end":91,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/managed-databases-mongodb/"}},{"start":230,"end":241,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.mongodb.com/","target":"_blank"}}]},{"type":"paragraph","text":"Managed MongoDB simplifies the MongoDB administration. Developers of all skill levels, even those who do not have prior experience in databases, can spin up MongoDB clusters in just a few minutes. We handle the provisioning, managing, scaling, updates, backups, and security of your MongoDB clusters, allowing you to offload the complex, time consuming –yet critical – database administration tasks to us. This empowers you to focus on what really matters: building awesome apps.","spans":[]},{"type":"embed","oembed":{"height":113,"width":200,"embed_url":"https://www.youtube.com/watch?v=NvHQSV7jnKA","type":"video","version":"1.0","title":"Create a MongoDB Database on DigitalOcean","author_name":"DigitalOcean","author_url":"https://www.youtube.com/c/Digitalocean","provider_name":"YouTube","provider_url":"https://www.youtube.com/","cache_age":null,"thumbnail_url":"https://i.ytimg.com/vi/NvHQSV7jnKA/hqdefault.jpg","thumbnail_width":480,"thumbnail_height":360,"html":"<iframe width=\"200\" height=\"113\" src=\"https://www.youtube.com/embed/NvHQSV7jnKA?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>"}},{"type":"heading2","text":"Benefits of Managed MongoDB","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"list-item","text":"Easy set up and maintenance: We create the database clusters for you. Simply choose the cluster configuration (e.g., memory, disk size, number of nodes, etc.), and the data center in which you want to host the database. Follow a few simple steps and your database cluster will be up and running in a matter of minutes. You can spin up clusters using the cloud control panel, CLI, or API.\n\n","spans":[{"start":0,"end":28,"type":"strong"}]},{"type":"list-item","text":"Automatic daily backups with point in time recovery: Data is one of the most important assets of an app, so it’s critical to backup your database. We take backups of your entire clusters automatically on a daily basis, for free. We also provide a point in time recovery for 7 days, that way if things go wrong due to human error, machine error, or some combination of both, you can easily restore the database as it was at any point in the previous 7 days. \n\n","spans":[{"start":0,"end":52,"type":"strong"}]},{"type":"list-item","text":"Automatic updates and access to latest MongoDB releases: You get access to MongoDB 4.4. This is the latest release of MongoDB and comes packed with numerous enhancements like hedged reads, rust, and swift drivers. Since we have developed Managed MongoDB in partnership with MongoDB Inc, you will always get access to new releases as they become available. With Managed MongoDB, the updates happen automatically. Just select a date and time for the updates and we take care of the rest. This makes it easy to stay up to date with MongoDB releases without disrupting your business.\n\n","spans":[{"start":0,"end":56,"type":"strong"},{"start":148,"end":169,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.mongodb.com/new","target":"_blank"}}]},{"type":"list-item","text":"High availability with automated failover: If your database goes down, it can take down the entire app, leading to bad customer experiences. With Managed MongoDB, you can easily minimize the downtime for your database and make it highly available with standby nodes. Standby nodes add redundancy, so if for example the primary node fails, the standby node is immediately promoted to primary and begins serving requests while we provision a replacement standby node in the background.\n\n","spans":[{"start":0,"end":42,"type":"strong"}]},{"type":"list-item","text":"Scale up easily to handle traffic spikes: As your app gains traction and the usage grows, it’s important to have a database that can keep up with the increased demand. With Managed MongoDB, you can easily scale up the size of database nodes when needed.\n\n","spans":[{"start":0,"end":41,"type":"strong"}]},{"type":"list-item","text":"Secure by default: Since data is critical, it also needs to be secure. We encrypt data at rest with LUKS and in transit with SSL. When you create a new cluster, it’s placed in a VPC network by default that provides a more secure connection between resources. You can also restrict access to your nodes to prevent brute-force password and denial-of-service attacks.","spans":[{"start":0,"end":18,"type":"strong"},{"start":178,"end":189,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/docs/networking/vpc/"}}]},{"type":"heading2","text":"The need for Managed Databases","spans":[]},{"type":"paragraph","text":"DigitalOcean’s mission is to simplify cloud computing so developers, startups, and SMBs can spend more time building software that changes the world. While databases are a critical component to any application, building, maintaining, and scaling them can be complex and time consuming. For developers that are building apps for their business, database administration is often not a core focus area. But it’s quite common to find developers that write the code and then also roll up their sleeves to maintain databases. Such users would rather offload the tedious database administration and focus their limited time and energy on building and enhancing their apps. ","spans":[]},{"type":"paragraph","text":"With this in mind, we introduced Managed Databases a couple of years ago and are excited to add Managed MongoDB to our portfolio. With this release, DigitalOcean Managed Databases now supports the following engines:","spans":[{"start":33,"end":50,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/managed-databases/"}}]},{"type":"image","url":"https://images.prismic.io/www-static/87745cc1-1c5f-4463-b104-104b7fc30dc7_managed-databases-logos.png?auto=compress,format","alt":null,"copyright":null,"dimensions":{"width":849,"height":104}},{"type":"paragraph","text":"Managed MongoDB launch comes on the heels of DigitalOcean App Platform, a modern, reimagined PaaS (Platform as a Service) that we released a few months ago. App Platform makes it very easy to build, deploy, and scale apps and static sites. You can deploy code by simply pointing to your GitHub and GitLab repos, and App Platform will do all the heavy lifting of managing infrastructure, app runtimes, and dependencies. App Platform, along with Managed Databases, helps fulfill DigitalOcean’s mission by empowering developers, startups, and SMBs to focus more on their apps, and less on the underlying infrastructure and databases.","spans":[{"start":45,"end":70,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/app-platform/"}}]},{"type":"heading2","text":"How Managed MongoDB works","spans":[]},{"type":"paragraph","text":"DigitalOcean provides you with various compute options to build your apps like:","spans":[]},{"type":"list-item","text":"Droplets: On-demand, Linux virtual machines suitable for production business applications and personal passion projects.","spans":[{"start":0,"end":8,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/droplets/"}}]},{"type":"list-item","text":"DigitalOcean Kubernetes: Managed Kubernetes with automatic scaling, upgrades, and a free control plane.","spans":[{"start":0,"end":23,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/kubernetes/"}}]},{"type":"list-item","text":"DigitalOcean App Platform: A fully managed Platform as a Service.","spans":[{"start":0,"end":25,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/app-platform/"}}]},{"type":"paragraph","text":"No matter which compute option you choose to build your apps, you can easily add Managed MongoDB to it. In addition to this, Managed MongoDB also integrates with the Node.js 1-Click App from DigitalOcean Marketplace making it a lot easier to build Node.js apps.","spans":[{"start":166,"end":215,"type":"hyperlink","data":{"link_type":"Web","url":"https://marketplace.digitalocean.com/apps/nodejs"}}]},{"type":"heading2","text":"Simple, predictable pricing","spans":[]},{"type":"paragraph","text":"Just like all DigitalOcean products, Managed MongoDB provides simple, predictable pricing that allows you to control costs and prevent any surprise bills. You can spin up a database cluster for just $15/month, or a highly available three-node replica set for $45/month. Click here for more information.","spans":[{"start":270,"end":301,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/pricing/#managed-databases"}}]},{"type":"heading2","text":"Regional availability","spans":[]},{"type":"paragraph","text":"Managed MongoDB is currently available in the following regions:","spans":[]},{"type":"list-item","text":"NYC3 (New York, USA)","spans":[]},{"type":"list-item","text":"FRA1 (Frankfurt, Germany)","spans":[]},{"type":"list-item","text":"AMS3 (Amsterdam, Netherlands)","spans":[]},{"type":"paragraph","text":"We will be making Managed Mongo available in other regions soon. Please check out the release notes for most up to date information on regional availability.","spans":[{"start":86,"end":99,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/docs/release-notes/"}}]},{"type":"heading2","text":"Join us at deploy, DigitalOcean’s virtual user conference","spans":[]},{"type":"paragraph","text":"Today we have deploy, DigitalOcean’s signature user conference, which focuses on celebrating, educating, and connecting awesome builders from all over the world.","spans":[{"start":14,"end":20,"type":"hyperlink","data":{"link_type":"Web","url":"https://deploy.digitalocean.com/home"}}]},{"type":"paragraph","text":"Check out the keynote session from DigitalOcean's CEO, Yancey Spruill, in which he talks about where we're headed as a company and shares some exciting product updates. His keynote will be followed by sessions from community members, engineers, customers, and other experts that are building technologies and businesses powered by the cloud. With live Q&A and an active Discord server, there’s ample opportunity to engage and learn something new. Click here to attend the deploy conference.","spans":[{"start":14,"end":69,"type":"hyperlink","data":{"link_type":"Web","url":"https://deploy.digitalocean.com/agenda/session/552806"}},{"start":347,"end":384,"type":"hyperlink","data":{"link_type":"Web","url":"http://do.co/deploy-discord"}},{"start":461,"end":489,"type":"hyperlink","data":{"link_type":"Web","url":"http://do.co/deploy"}}]},{"type":"paragraph","text":"We are also launching a hackathon for DigitalOcean Managed MongoDB. Learn how you can participate, submit an app and get a t-shirt.","spans":[{"start":24,"end":66,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/mongodb-hackathon"}}]},{"type":"paragraph","text":"We hope you will give Managed MongoDB a try. Here are some sample datasets and sample apps that you can use to kick the tires. Check out the docs and let us know what you think!","spans":[{"start":22,"end":43,"type":"hyperlink","data":{"link_type":"Web","url":"https://cloud.digitalocean.com/databases/new?engine=mongodb"}},{"start":59,"end":90,"type":"hyperlink","data":{"link_type":"Web","url":"https://github.com/do-community/mongodb-resources","target":"_blank"}},{"start":141,"end":145,"type":"hyperlink","data":{"link_type":"Web","url":"https://docs.digitalocean.com/products/databases/mongodb/"}}]},{"type":"paragraph","text":"If you’d like to have a conversation about using DigitalOcean and Managed MongoDB in your business, please feel free to contact our sales team.","spans":[{"start":120,"end":142,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/company/contact/sales/"}}]},{"type":"paragraph","text":"Happy coding!","spans":[]},{"type":"paragraph","text":"André Bearfield","spans":[]},{"type":"paragraph","text":"Director of Product Management","spans":[]}],"tags":[{"tag1":{"__typename":"PRISMIC_Tag","tag":"Product Updates","_linkType":"Link.document","_meta":{"uid":"product-updates"}}}],"author":{"__typename":"PRISMIC_Author","author_name":"André Bearfield","author_image":{"dimensions":{"width":553,"height":547},"alt":"André Bearfield","copyright":null,"url":"https://images.prismic.io/www-static/fdc7c85186f0a850b04083e1d4306bd1c19772e8_andre-bearfield.png?auto=compress,format"},"_meta":{"uid":"andre-bearfield"}},"_meta":{"uid":"introducing-digitalocean-managed-mongodb"}},"featured_blog_2":{"__typename":"PRISMIC_Blog","_linkType":"Link.document","blog_header_image":{"dimensions":{"width":790,"height":400},"alt":"Droplet Console","copyright":null,"url":"https://images.prismic.io/www-static/710499ae-78cc-4179-afc1-15793637b200_DODX3727-790x400-logo-2.jpg?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Securely connect to Droplets with SSH key pairs using a new Droplet Console","spans":[]}],"blog_post_date":"2021-08-10","blog_post_content":[{"type":"paragraph","text":"The famous author Ken Blanchard once said, “Feedback is the breakfast of champions.\" This is something we truly believe at DigitalOcean, and we always strive to enhance our products based on customer feedback.","spans":[]},{"type":"paragraph","text":"With this goal in mind, we are excited to introduce a new Droplet Console that will make it much easier to connect to your Droplets securely. The new Droplet Console provides one-click SSH access to your Droplets through a native-like SSH/Terminal experience. It also eliminates the need for a password or manual configuration of SSH keys. Starting today, we’re pleased to announce that the new Droplet Console is now available to all Droplet users.","spans":[]},{"type":"heading2","text":"Why you should be using Secure Shell (SSH) ","spans":[]},{"type":"paragraph","text":"Password-based security is notoriously insecure due to password fatigue and the overuse of passwords such as ‘123456’. Secure Shell or SSH is a network communication protocol that solves this by using passwordless solutions for encryption, enabling two computers to communicate and securely share data. At a high level, SSH works by creating cryptographic key pairs consisting of a public and private key, which are computer generated and stored separately to ensure their security. ","spans":[{"start":80,"end":117,"type":"hyperlink","data":{"link_type":"Web","url":"https://cybernews.com/best-password-managers/most-common-passwords/"}}]},{"type":"paragraph","text":"SSH has become the default encryption protocol for many industries, but it was difficult to use SSH keys with DigitalOcean’s current Recovery (VNC) console, which is why we developed our new Droplet Console. The new Droplet Console is backed by an agent that security supervises the key pair, while also providing one-click SSH access to our users. You can see the full list of features below.","spans":[]},{"type":"heading2","text":"The new Droplet Console: More time saving, less time wasting ","spans":[]},{"type":"paragraph","text":"The new Droplet Console is for everyone who is looking to build fast, secure apps and avoid hassles with SSH access & usability issues.","spans":[]},{"type":"paragraph","text":"In addition to easier SSH access, the new Droplet Console comes with:","spans":[]},{"type":"list-item","text":"Copy/paste text: Instead of typing lengthy key pairs and text manually, you can use copy/paste to save time. ","spans":[{"start":0,"end":17,"type":"strong"}]},{"type":"list-item","text":"Multi-color support: Multi-color support makes the console more useful and intuitive, and breaks the conventional standard appearance which is black text on a white background. ","spans":[{"start":0,"end":41,"type":"strong"}]},{"type":"list-item","text":"Multi-language support: DigitalOcean’s new Droplet Console supports multiple languages, meaning you can now type and view any content in any language that is supported by UTF-8","spans":[{"start":0,"end":24,"type":"strong"}]},{"type":"list-item","text":"OS/images supported: Linux distributions (Ubuntu(16.04 - 20.04), Fedora (32 & 33), Debian (9), CentOS (7.6 & 8.3), CentOS 8 Stream, Rocky Linux and Marketplace images.","spans":[{"start":0,"end":20,"type":"strong"},{"start":148,"end":159,"type":"hyperlink","data":{"link_type":"Web","url":"https://marketplace.digitalocean.com/"}}]},{"type":"paragraph","text":"The new Droplet Console is available by default on any new Droplets you spin up. You can also enable it manually on older Droplets. Click here to learn more!","spans":[{"start":132,"end":157,"type":"hyperlink","data":{"link_type":"Web","url":"https://docs.digitalocean.com/products/droplets/how-to/connect-with-console/"}}]},{"type":"paragraph","text":"Check out this short walkthrough video that shows the new Droplet Console in action: ","spans":[]},{"type":"embed","oembed":{"type":"video","embed_url":"https://www.youtube.com/watch?v=Qt7QihVuxiE","title":"Access Your Droplet Terminal Through the Web Console","provider_name":"YouTube","thumbnail_url":"https://i.ytimg.com/vi/Qt7QihVuxiE/hqdefault.jpg","provider_url":"https://www.youtube.com/","author_name":"DigitalOcean","author_url":"https://www.youtube.com/c/Digitalocean","height":113,"width":200,"version":"1.0","thumbnail_height":360,"thumbnail_width":480,"html":"<iframe width=\"200\" height=\"113\" src=\"https://www.youtube.com/embed/Qt7QihVuxiE?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>"}},{"type":"paragraph","text":"We hope you’re excited about the new Droplet Console. You’re welcome to spin some Droplets up right now, and try out the new Droplet Console – why wait?","spans":[{"start":72,"end":103,"type":"hyperlink","data":{"link_type":"Web","url":"https://cloud.digitalocean.com/droplets/new"}}]},{"type":"paragraph","text":"Happy coding!","spans":[]},{"type":"paragraph","text":"Harsh Banwait, Senior Product Manager","spans":[]}],"tags":[{"tag1":{"__typename":"PRISMIC_Tag","tag":"Product Updates","_linkType":"Link.document","_meta":{"uid":"product-updates"}}}],"author":{"__typename":"PRISMIC_Author","author_name":"Harsh Banwait","author_image":{"dimensions":{"width":600,"height":399},"alt":null,"copyright":null,"url":"https://images.prismic.io/www-static/e83ff690-b20c-4d88-a2b6-57e562558cd6_download.png?auto=compress,format"},"_meta":{"uid":"harsh-banwait"}},"_meta":{"uid":"new-droplet-console-ssh-support"}},"featured_blog_3":{"__typename":"PRISMIC_Blog","_linkType":"Link.document","blog_header_image":{"dimensions":{"width":790,"height":400},"alt":null,"copyright":null,"url":"https://images.prismic.io/www-static/588e28d3-d41e-480b-937b-8c3b19201f6e_DODX3568-790x400-Blog.jpg?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"How to scale your SaaS product without breaking the bank","spans":[]}],"blog_post_date":"2021-06-22","blog_post_content":[{"type":"paragraph","text":"These days, if you are in the business of software, chances are you are delivering or plan to deliver your services using a Software-as-a-Service (SaaS) model. A combination of internet-based delivery, subscription-based pricing, and low-friction product experiences have made SaaS solutions valuable tools for their users, and an excellent vehicle for software builders looking to distribute their products.","spans":[]},{"type":"paragraph","text":"These factors have made SaaS solutions ubiquitous; SaaS is the largest segment in the public cloud market, and is used to provide functionality ranging from personal finance apps for consumers, to productivity software for businesses, and even tools and services for software developers themselves to compose their applications and simplify their workflows. It is also not uncommon to find micro-SaaS applications being built for specific industries such as retail, job functions such as accounting or marketing, or tasks such as event management. ","spans":[]},{"type":"paragraph","text":"The best thing about this SaaS wave has been that it has allowed a new generation of software builders to build and monetize applications and participate in the digital economy. Previously, you had to be a big company with lots of resources, name recognition and distribution networks to successfully sell software products. Now, irrespective of whether you are a single person working on a passion project, a small team of developers in a startup, or a small and medium-sized business (SMB), the SaaS model enables you to express your ideas in the form of software and deliver them to customers anywhere in the world.","spans":[]},{"type":"heading2","text":"The unique challenges of building SaaS solutions","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Despite the opportunities that come with the widespread adoption of SaaS products, software builders still have to answer key questions in their journey to building successful SaaS products. Understanding what customers to target, features to prioritize, how to price your product, and how to acquire customers are all critical questions to figure out while you are also doing the important job of actually building and operating the product. ","spans":[]},{"type":"paragraph","text":"Writing the code, testing, deployment, monitoring the usage in production, and ensuring that your apps are able to handle the additional demand when customer base and usage grows are all essential and time-consuming tasks.","spans":[]},{"type":"paragraph","text":"Additionally, being able to test multiple ideas, pivot, and double down on the ideas that actually work is critical in early stages of SaaS development. Once growth comes, it is equally important to scale up without compromising on performance or reliability. Needless to say, all of this needs to be economically viable as well, since not everyone has the resources of large SaaS providers like Salesforce or Adobe.","spans":[]},{"type":"heading2","text":"Cloud Computing enables builders but also poses challenges","spans":[]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Fortunately, for the act of building and operating your apps, cloud computing can help take some load off your shoulders. Unless you have the scale and resources of Facebook, chances are you are not going to set up your own data centers to host the computing infrastructure that powers your SaaS company. Public cloud infrastructure providers can bring great value to SaaS builders by providing on-demand computing services with usage-based pricing. However, just like how the legacy software companies weren't built for the SaaS model, the early (and big) cloud computing services were not optimized for the unique needs of small SaaS building teams. ","spans":[]},{"type":"paragraph","text":"Smaller SaaS teams face challenges with large cloud computing providers, including:","spans":[]},{"type":"heading4","text":"Too many technology options","spans":[]},{"type":"paragraph","text":"There are just too many options for tech stacks on which to build your SaaS - programming languages, application development frameworks, libraries, runtime environments, architectural patterns, and deployment models - and the list is growing by the day.","spans":[]},{"type":"heading4","text":"Complexity of cloud computing services","spans":[]},{"type":"paragraph","text":"Even when you have decided on a technology stack, there is a lot of cloud vendor-specific terminology you need to learn and heavy lifting you need to do to build on the cloud, not all of which contributes to making your SaaS applications successful.","spans":[]},{"type":"heading4","text":"Unpredictable costs","spans":[]},{"type":"paragraph","text":"The experimentation necessary in early stages of SaaS development, as well as the scaling of applications required during the growth phase, call for affordable and predictable pricing from your cloud provider. The last thing SaaS teams want is surprising and indecipherable bills from your cloud provider. Unfortunately, smaller businesses often experience unpredictable costs with cloud providers who are busy serving only the large enterprises.","spans":[]},{"type":"heading2","text":"DigitalOcean provides a simple, cost effective solution for SaaS builders","spans":[]},{"type":"paragraph","text":"Fortunately, at DigitalOcean we have a laser focus on small software development teams, who are trying to build the next generation of applications. Today, DigitalOcean customers are already building SaaS applications which serve all kinds of customers.","spans":[{"start":191,"end":217,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/solutions/saas/"}}]},{"type":"paragraph","text":"We believe SaaS builders should focus on building apps that power their business, and not spend their valuable time on managing infrastructure. That is exactly what we have been able to enable through our intuitive products that are built for scale and reliability.","spans":[{"start":205,"end":223,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/"}}]},{"type":"list-item","text":"Vidazoo is an advertising technology company specializing in video streaming and serving. It serves video ads to thousands of websites and handles close to 10 billion requests per day. \n\n“We are as much a data company as an adtech company. Our business relies on speedy and accurate data processing at massive scale. DigitalOcean provides us the perfect set of tools to operate our SaaS business profitably, while not making us feel the need to become full time system administrators. We plan to move a lot of our apps to DigitalOcean App Platform and other fully managed products.” - Roman Svichar, CTO of Vidazoo","spans":[{"start":0,"end":7,"type":"hyperlink","data":{"link_type":"Web","url":"https://vidazoo.com/"}},{"start":187,"end":583,"type":"em"}]},{"type":"paragraph","text":"We believe in meeting customers where they are. If they already have an understanding of cloud infrastructure technologies, they should be able to leverage that knowledge and get started with our products without any further ramp up.","spans":[]},{"type":"list-item","text":"Whatfix is an enterprise SaaS provider that offers a digital adoption platform to businesses. The company helps enterprises gain the full value of their investments in enterprise applications by providing real-time, interactive, and contextual guidance to users of those applications. \n\n“What we really love about the DigitalOcean platform is the ease of use. We feel like we know infrastructure and can handle most of the configuration and management. What we needed from a cloud was not bells and whistles but efficiency and reliability. DigitalOcean provides us a platform to build our apps and then gets out of the way. Just how we like it.” - Achyuth Krishna, Director of Engineering of Whatfix","spans":[{"start":0,"end":7,"type":"hyperlink","data":{"link_type":"Web","url":"https://whatfix.com/blog/driving-the-future-now-were-excited-to-announce-our-90-million-series-d-funding/"}},{"start":287,"end":648,"type":"em"}]},{"type":"paragraph","text":"We understand that scaling while maintaining reliability of applications and profitability of business is important, so we provide robust solutions which minimize downtime.","spans":[]},{"type":"list-item","text":"Centra is a SaaS-based e-commerce platform for global direct-to-consumer and wholesale e-commerce brands. Centra provides a powerful e-commerce backend that lets brands build pixel-perfect, custom designed, online flagship stores. \n\n“How do we enable our customers to create differentiated online experiences? How do we ensure their e-commerce apps stay up and running at all times? How do we scale on-demand when traffic grows or new customers come in? These are the questions that we ask ourselves every day. Thankfully, we have a partner in DigitalOcean that provides just the platform to answer those questions enabling us to guarantee 99.9% uptime for our clients.” - Martin Jensen, CEO of Centra","spans":[{"start":0,"end":6,"type":"hyperlink","data":{"link_type":"Web","url":"https://centra.com/"}},{"start":233,"end":673,"type":"em"}]},{"type":"paragraph","text":"These are just a few examples of SaaS businesses finding success on DigitalOcean. We are constantly amazed by the creativity and innovation that software builders are utilizing our platform for. If you are interested in learning more about product updates, technical deep-dives and best practices for building SaaS products and businesses, please contact us to learn how we can help you get started. ","spans":[{"start":340,"end":357,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/migrate/?utmmedium=blog","target":"_blank"}}]},{"type":"paragraph","text":"Come build with DigitalOcean!","spans":[]},{"type":"paragraph","text":"Looking to migrate your SaaS to DigitalOcean? Leverage free infrastructure credits, robust training, and technical support to ensure a worry-free migration.","spans":[{"start":0,"end":156,"type":"strong"},{"start":0,"end":156,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/migrate/?utmmedium=blog","target":"_blank"}}]},{"type":"paragraph","text":"","spans":[]},{"type":"paragraph","text":"Raman Sharma","spans":[]},{"type":"paragraph","text":"Vice President, Product & Programs Marketing","spans":[]}],"tags":[{"tag1":{"__typename":"PRISMIC_Tag","tag":"Developer Relations","_linkType":"Link.document","_meta":{"uid":"developer-relations"}}}],"author":{"__typename":"PRISMIC_Author","author_name":"Raman Sharma","author_image":{"dimensions":{"width":512,"height":512},"alt":null,"copyright":null,"url":"https://images.prismic.io/www-static/497b4b14-d192-493a-8b66-7ae176ba99f3_raman.png?auto=compress,format"},"_meta":{"uid":"raman-sharma"}},"_meta":{"uid":"how-to-scale-your-saas-product-without-breaking-the-bank"}}}}]}}},"pageContext":{"limit":12,"skip":132,"numPages":33,"currentPage":12,"data":[{"node":{"author":{"_linkType":"Link.document","author_name":"Kenneth Reitz","author_image":{"dimensions":{"width":1000,"height":667},"alt":"Kenneth Reitz","copyright":null,"url":"https://images.prismic.io/www-static/a7da1b896a3f5366e6be9c9594fc7668e1094197_dscf3147.jpg?auto=compress,format"},"_meta":{"uid":"kenneth_reitz"}},"blog_header_image":{"dimensions":{"width":800,"height":600},"alt":"lighthouse","copyright":null,"url":"https://images.prismic.io/www-static/d3aad1c2-29a8-4c99-b211-0212aa4ac7f6_qa-dribbble.png?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Some Postgres Best Practices","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"Over my many years of serving as a Developer Relations Advocate, I’ve met and spoken with thousands of developers all over the world about their database configurations, and many have shared with me their lessons learned.","spans":[]},{"type":"paragraph","text":"To celebrate the launch of our new managed database product, I'd like to share a few key takeaways you might apply to your new managed PostgreSQL databases.","spans":[{"start":31,"end":59,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/managed-databases/"}},{"start":127,"end":155,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/docs/databases/"}}]},{"type":"heading3","text":"Use Connection Strings & Environment Variables","spans":[]},{"type":"paragraph","text":"The Twelve Factors, a set of best practices for building web applications for the cloud, is very clear about one thing: never store your database credentials in your codebase! Your code should be considered both proprietary and of inherent value, while at the same time being considered inherently insecure. Your data is what’s truly valuable.","spans":[{"start":0,"end":18,"type":"hyperlink","data":{"link_type":"Web","url":"https://12factor.net/"}}]},{"type":"paragraph","text":"So, to provide trusted credentials to trusted code, we recommend exposing the connection string of your Postgres database as an environment variable, named ```[php]{`DATABASE_URL`}```. Every common web framework has support for this (e.g., with Django, see dj-database-url).  ","spans":[{"start":257,"end":272,"type":"hyperlink","data":{"link_type":"Web","url":"https://pypi.org/project/dj-database-url/"}}]},{"type":"heading3","text":"Rotate Credentials Regularly","spans":[]},{"type":"paragraph","text":"It’s a good idea to rotate your database credentials periodically, across your organization. However, during special times, like when offboarding a member of the team, it’s important to rotate the credentials to the Managed Databases and Spaces they had access to.","spans":[]},{"type":"paragraph","text":"All it takes is one stray ```[php]{`.env`}``` file from a couple of years ago to get into the wrong hands, and then your entire infrastructure could be instantly compromised. I recommend having organization-wide quarterly “credential rotation” days, with hard deadlines. This (likely) tedious process will be forced to become streamlined as your team continues to rotate the credentials month after month, encouraging automation. It’s best for everyone. ","spans":[]},{"type":"heading3","text":"Use BIGINT or UUID for Primary Keys","spans":[]},{"type":"paragraph","text":"A big mistake in a lot of applications is using `INT` instead of `BIGINT` for primary keys (every Django application does this by default, for example).","spans":[]},{"type":"paragraph","text":"When you use ```[php]{`INT`}``` instead of ```[php]{`BIGINT`}```, eventually, one day, the value in your database exceeds the “storage capacity” of an ```[php]{`INT`}```, and a ```[php]{`BIGINT`}``` must be migrated to. The migration time to convert a table from ```[php]{`INT`}``` to ```[php]{`BIGINT`}``` usually takes around 4 hours, once the problem has been located.","spans":[]},{"type":"paragraph","text":"```[php]{`BIGINT`}``` is much more appropriate as a default PK, and is not that much more expensive to store or index.","spans":[]},{"type":"paragraph","text":"I personally use UUIDs in all of my databases: ","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    -- Enable pgcrypto for UUID support.","spans":[]},{"type":"paragraph","text":"    CREATE EXTENSION pgcrypto;","spans":[]},{"type":"paragraph","text":"    ","spans":[]},{"type":"paragraph","text":"    -- Table: notes","spans":[]},{"type":"paragraph","text":"    CREATE TABLE notes (  ","spans":[]},{"type":"paragraph","text":"        uuid UUID DEFAULT gen_random_uuid(),","spans":[]},{"type":"paragraph","text":"        body text  NOT NULL,","spans":[]},{"type":"paragraph","text":"        byline text,","spans":[]},{"type":"paragraph","text":"        CONSTRAINT notes_pk PRIMARY KEY (uuid)","spans":[]},{"type":"paragraph","text":"    );","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"paragraph","text":"Learn more about uuid4 / pgcrypto in Postgres.","spans":[{"start":0,"end":45,"type":"hyperlink","data":{"link_type":"Web","url":"https://til.hashrocket.com/posts/64b5949eac-generating-uuids-with-pgcrypto"}}]},{"type":"heading3","text":"Use Connection Pooling","spans":[]},{"type":"paragraph","text":"When connecting to a high-throughput Postgres database server, it’s considered best practice to configure your clients to use PgBouncer, a lightweight connection pooler for PostgreSQL, instead of connecting to the database server directly.","spans":[{"start":126,"end":135,"type":"hyperlink","data":{"link_type":"Web","url":"https://wiki.postgresql.org/wiki/PgBouncer"}}]},{"type":"paragraph","text":"Connection pooling has many performance advantages, and will make the query performance characteristics of your database much more deterministic.","spans":[{"start":28,"end":50,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/managed-databases-connection-pools-and-postgresql-benchmarking-using-pgbench"}}]},{"type":"paragraph","text":"However, here at DigitalOcean, we take care of that for you! So, there’s no need to run your own instance of PgBouncer when using DigitalOcean Postgres, as it’s already provided and pre-tuned out of the box. Simplicity at scale.","spans":[{"start":34,"end":59,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/docs/databases/how-to/postgresql/manage-connection-pools/"}}]},{"type":"heading3","text":"Further Reading","spans":[]},{"type":"paragraph","text":"Here are some further resources for upping your Postgres game:","spans":[]},{"type":"list-item","text":"Postgres Guide","spans":[{"start":0,"end":14,"type":"hyperlink","data":{"link_type":"Web","url":"http://postgresguide.com/"}}]},{"type":"list-item","text":"Managed Databases Connection Pools and PostgreSQL Benchmarking","spans":[{"start":0,"end":62,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/managed-databases-connection-pools-and-postgresql-benchmarking-using-pgbench"}}]},{"type":"paragraph","text":"Happy hacking! ","spans":[]},{"type":"paragraph","text":"Kenneth Reitz (@kennethreitz) ","spans":[{"start":15,"end":28,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/kennethreitz"}}]},{"type":"paragraph","text":"Developer Relations Advocate","spans":[]}],"blog_post_date":"2019-03-04","tags":[{"tag1":{"tag":"Developer Relations","_linkType":"Link.document","_meta":{"uid":"developer-relations"}}}],"_meta":{"uid":"some-postgres-best-practices"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"Karan Chhina","author_image":{"dimensions":{"width":554,"height":550},"alt":"Karan Chhina","copyright":null,"url":"https://images.prismic.io/www-static/b43a85223ca42f817f454615a86497acf668d7c3_karan.png?auto=compress,format"},"_meta":{"uid":"karan_chhina"}},"blog_header_image":{"dimensions":{"width":1200,"height":600},"alt":"droplets illustration","copyright":null,"url":"https://images.prismic.io/www-static/0026a57b93abe5b04413765253903472dab58e11_general-droplets_blog-v4_twitter---facebook.png?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Introducing General Purpose Droplets: Dedicated vCPUs and More Memory","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"In our 2019 product roadmap update, we highlighted our push up-stack into an Application Marketplace, a managed Kubernetes service, and multiple Managed Database offerings. We're complementing these products by investing in expanding our Droplet infrastructure offerings to help you build and deploy amazing apps.","spans":[{"start":7,"end":34,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/whats-new-for-2019/"}}]},{"type":"paragraph","text":"We received positive feedback from users when we launched our CPU-Optimized Droplets. At the same time, we heard from users that they wanted the same performance and predictability of dedicated CPU resources, but with higher configurations of RAM. Today, we’re pleased to announce General Purpose Droplets (in Limited Availability) to fill that need.","spans":[{"start":62,"end":84,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/docs/droplets/overview/#cpu-optimized-droplets"}}]},{"type":"heading3","text":"What Are General Purpose Droplets?","spans":[]},{"type":"paragraph","text":"General Purpose Droplets are optimized to deliver a well-proportioned balance of memory, dedicated CPU, and SSD storage resources. They’re ideal for a variety of application workloads ranging from web apps and databases to larger applications that have higher memory requirements and still demand predictable CPU performance. Some of the use cases for these Droplets are:","spans":[]},{"type":"list-item","text":"Web application hosting","spans":[]},{"type":"list-item","text":"Relational and NoSQL databases","spans":[]},{"type":"list-item","text":"In-memory caches","spans":[]},{"type":"list-item","text":"E-commerce sites and analytics applications","spans":[]},{"type":"list-item","text":"Various enterprise business applications","spans":[]},{"type":"paragraph","text":"General Purpose Droplets are backed by Intel’s highly performant Xeon Platinum 8168 processors with a clock speed of 2.7GHz and are available in six different configurations ranging from 2 vCPU / 8 GB RAM to 40 vCPU / 160 GB RAM (plan details below). This translates into a 1:4 ratio of dedicated vCPU to memory for most of these plan configurations, which is an ideal ratio of compute to memory requirements for most general-purpose, mainstream applications. Additionally, these plans come with the same highly performant attached SSD storage that our users love on all of our Droplets.","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/0c83e76fa3bf05f70a8c7a91014abc5608536254_droplet_lineup.jpg?auto=compress,format","alt":null,"copyright":null,"dimensions":{"width":1500,"height":847}},{"type":"heading3","text":"Performance Class of Droplets Are Production-Grade","spans":[]},{"type":"paragraph","text":"Together, General Purpose Droplets and CPU-Optimized Droplets form our Performance Class of Droplets - virtual machines that offer dedicated hyper-threads from best-in-class Intel processors in a variety of configurations.","spans":[]},{"type":"paragraph","text":"How do Performance Class Droplets compare to Standard Droplets? Our original Droplet plans, used by millions of developers around the world, offer a variety of shared-CPU configurations that are ideal for running workloads that can handle variable levels of CPU performance and can spike CPU usage as needed. Typical use cases include small web servers, blogs, and dev/test environments.","spans":[]},{"type":"heading3","text":"Plans, Pricing and Availability","spans":[]},{"type":"paragraph","text":"General Purpose Droplets are available in the following configurations:","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/503904e62aa183c331a2b9a2ddd3c4a59c7e4de8_general-purpose-pricing-table.png?auto=compress,format","alt":null,"copyright":null,"dimensions":{"width":1744,"height":842}},{"type":"paragraph","text":"General Purpose Droplets are currently available under Limited Availability, and can be provisioned in two data centers – New York (NYC1) and Frankfurt (FRA1). Over the next few weeks we have expansion plans to make these Droplets available in additional data centers globally, so stay tuned. Meanwhile, we hope you head over to the Create Droplet page and take these new Droplets for a swim, eh, spin.","spans":[{"start":55,"end":75,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/docs/platform/product-lifecycle/#limited-availability"}},{"start":333,"end":347,"type":"hyperlink","data":{"link_type":"Web","url":"https://cloud.digitalocean.com/droplets/new"}}]},{"type":"paragraph","text":"Happy coding,","spans":[]},{"type":"paragraph","text":"Karan Chhina","spans":[]},{"type":"paragraph","text":"Senior Product Manager, Compute","spans":[]}],"blog_post_date":"2019-02-26","tags":[{"tag1":{"tag":"Product Updates","_linkType":"Link.document","_meta":{"uid":"product-updates"}}}],"_meta":{"uid":"introducing-general-purpose-droplets-dedicated-vcpus-and-more-memory"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"Kamal Nasser","author_image":{"dimensions":{"width":1008,"height":1008},"alt":null,"copyright":null,"url":"https://images.prismic.io/www-static/e2285fcfaf32ce7ec26329fe7e416ae896fbf991_portrait_2k18_bw_smallres.jpg?auto=compress,format"},"_meta":{"uid":"kamal-nasser"}},"blog_header_image":{"dimensions":{"width":1200,"height":900},"alt":null,"copyright":null,"url":"https://images.prismic.io/www-static/cfc9e5e6-a7f9-4565-8023-a8a94fd572fb_database-mostov_dribbble.png?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Creating a Simple Contacts List with Laravel and PostgreSQL","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"In this post, we will build a simple Laravel app that displays a contacts list on a page. Using Eloquent and PostgreSQL's JSON object support, the app will query the database for the contacts and their details. This is what the result will look like:","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/03a96195-00d0-4aa8-8c94-d05375d015f6_Kamal-1.png?auto=compress,format","alt":null,"copyright":null,"dimensions":{"width":1600,"height":1396}},{"type":"paragraph","text":"By doing this, you will learn how to connect Laravel to a DigitalOcean Managed PostgreSQL database cluster, initialize the database with random data using Laravel factories and seeders, and store and read JSON documents in PostgreSQL using Laravel Eloquent.","spans":[{"start":58,"end":106,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/announcing-managed-databases-for-postgresql/"}}]},{"type":"heading2","text":"Requirements","spans":[]},{"type":"paragraph","text":"This post assumes that you have a working PHP development environment. You will need:","spans":[]},{"type":"list-item","text":"PHP 7.1+","spans":[]},{"type":"list-item","text":"Composer","spans":[{"start":0,"end":8,"type":"hyperlink","data":{"link_type":"Web","url":"https://getcomposer.org/doc/00-intro.md#installation-linux-unix-macos"}}]},{"type":"list-item","text":"Laravel’s required PHP extensions","spans":[{"start":10,"end":33,"type":"hyperlink","data":{"link_type":"Web","url":"https://laravel.com/docs/5.7/installation#server-requirements"}}]},{"type":"heading2","text":"Step 1: Create a Base Laravel App","spans":[]},{"type":"paragraph","text":"Let's start by creating a new blank Laravel app that will serve as a base for our web app. In a directory of your liking, generate a new project using Composer:","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    composer create-project --prefer-dist laravel/laravel laravel-contacts","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"paragraph","text":"If you browse into the newly-created `laravel-contacts` directory and run Laravel's built-in web server, you will see the default Laravel welcome page:","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    cd laravel-contacts","spans":[]},{"type":"paragraph","text":"    php artisan serve","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/67fc2310-14e8-420c-b837-1c583b84708b_Kamal-2.png?auto=compress,format","alt":null,"copyright":null,"dimensions":{"width":1600,"height":869}},{"type":"paragraph","text":"Let's think about what our app will need. We want to have a list of contacts, so the database will store them. This means that we will need a ```[php]{`Contact`}``` model and a migration for the ```[php]{`contacts`}``` table. We'll also want to initialize the database with some random contacts so we have something to see, which will require a ```[php]{`Contact`}``` Factory and Seeder. ","spans":[]},{"type":"paragraph","text":"Let's build them out step by step:","spans":[]},{"type":"heading2","text":"Step 2: Create the Contact Model","spans":[]},{"type":"paragraph","text":"As shown in the screenshot above, a contact will have the following properties:","spans":[]},{"type":"list-item","text":"Name","spans":[]},{"type":"list-item","text":"Phone Number","spans":[]},{"type":"list-item","text":"Address","spans":[]},{"type":"list-item","text":"Favorite Colors","spans":[]},{"type":"paragraph","text":"For the favorite colors property, we will make use of Postgres's JSON data type. We will create a generic \"favorites\" column that will contain a JSON object with a list of favorite things. In this post we will store favorite colors only, but using a generic “favorites” object allows us to add different types in the future.","spans":[]},{"type":"paragraph","text":"Generate a model, factory, and migration using ```[php]{`artisan`}```:","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    php artisan make:model -f -m Contact","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"paragraph","text":"Now we'll configure the different parts of the model.","spans":[]},{"type":"heading3","text":"Migration","spans":[]},{"type":"paragraph","text":"Edit the generated migration file stored in ```[php]{`database/migrations/*_create_contacts_table.php`}```. Inside the ```[php]{`Schema::create()`}``` block, we will define the structure of the table:","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    <?php  ","spans":[]},{"type":"paragraph","text":"    use Illuminate\\Support\\Facades\\Schema;  ","spans":[]},{"type":"paragraph","text":"    use Illuminate\\Database\\Schema\\Blueprint;  ","spans":[]},{"type":"paragraph","text":"    use Illuminate\\Database\\Migrations\\Migration;  ","spans":[]},{"type":"paragraph","text":"    class CreateContactsTable extends Migration  ","spans":[]},{"type":"paragraph","text":"    {","spans":[]},{"type":"paragraph","text":"        /**","spans":[]},{"type":"paragraph","text":"          * Run the migrations.","spans":[]},{"type":"paragraph","text":"          *","spans":[]},{"type":"paragraph","text":"          * @return void","spans":[]},{"type":"paragraph","text":"          */","spans":[]},{"type":"paragraph","text":"        public function up()","spans":[]},{"type":"paragraph","text":"        {","spans":[]},{"type":"paragraph","text":"            Schema::create('contacts', function (Blueprint $table) {","spans":[]},{"type":"paragraph","text":"                $table->increments('id');","spans":[]},{"type":"paragraph","text":"                $table->string('name');","spans":[]},{"type":"paragraph","text":"                $table->string('phone');","spans":[]},{"type":"paragraph","text":"                $table->string('address');","spans":[]},{"type":"paragraph","text":"                $table->jsonb('favorites')->default('{}');","spans":[]},{"type":"paragraph","text":"                $table->timestamps();","spans":[]},{"type":"paragraph","text":"            });","spans":[]},{"type":"paragraph","text":"        }","spans":[]},{"type":"paragraph","text":"        /**","spans":[]},{"type":"paragraph","text":"            * Reverse the migrations.","spans":[]},{"type":"paragraph","text":"            *","spans":[]},{"type":"paragraph","text":"            * @return void","spans":[]},{"type":"paragraph","text":"            */","spans":[]},{"type":"paragraph","text":"        public function down()","spans":[]},{"type":"paragraph","text":"        {","spans":[]},{"type":"paragraph","text":"            Schema::dropIfExists('contacts');","spans":[]},{"type":"paragraph","text":"        }","spans":[]},{"type":"paragraph","text":"    }","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"paragraph","text":"This will configure the database column as described above with the `favorites` column set to a JSON object. The default value is an empty object.","spans":[]},{"type":"heading3","text":"Random Contact Generation","spans":[]},{"type":"paragraph","text":"The contact factory generates random values for a contact. We will configure a seeder that will use the factory to insert 10 random contacts to the database. This will provide us with an option to seed the database with random contacts when running the migration. Let's start with the factory.","spans":[]},{"type":"heading4","text":"Factory","spans":[]},{"type":"paragraph","text":"Edit the generated factory file stored in ```[php]{`database/factories/ContactFactory.php`}```. First, we will generate three random colors to use as favorites:","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    $colors = collect(range(1, 3))->map(function() use ($faker) {","spans":[]},{"type":"paragraph","text":"        return $faker->colorName;","spans":[]},{"type":"paragraph","text":"    })->toArray();","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"paragraph","text":"We will use these colors along with other data generated using the Faker library to return the contact's properties:","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    return [","spans":[]},{"type":"paragraph","text":"        'name' => $faker->name,","spans":[]},{"type":"paragraph","text":"        'phone' => $faker->e164PhoneNumber,","spans":[]},{"type":"paragraph","text":"        'address' => $faker->address,","spans":[]},{"type":"paragraph","text":"        'favorites' => ['colors' => $colors],","spans":[]},{"type":"paragraph","text":"    ];","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"paragraph","text":"The resulting factory should look like this:","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    <?php","spans":[]},{"type":"paragraph","text":"    ","spans":[]},{"type":"paragraph","text":"    use Faker\\Generator as Faker;","spans":[]},{"type":"paragraph","text":"    ","spans":[]},{"type":"paragraph","text":"    $factory->define(App\\Contact::class, function (Faker $faker) {","spans":[]},{"type":"paragraph","text":"        // generate 3 random colors","spans":[]},{"type":"paragraph","text":"        $colors = collect(range(1, 3))->map(function() use ($faker) {","spans":[]},{"type":"paragraph","text":"            return $faker->colorName;","spans":[]},{"type":"paragraph","text":"        })->toArray();","spans":[]},{"type":"paragraph","text":"    ","spans":[]},{"type":"paragraph","text":"        return [","spans":[]},{"type":"paragraph","text":"            'name' => $faker->name,","spans":[]},{"type":"paragraph","text":"            'phone' => $faker->e164PhoneNumber,","spans":[]},{"type":"paragraph","text":"            'address' => $faker->address,","spans":[]},{"type":"paragraph","text":"            'favorites' => ['colors' => $colors],","spans":[]},{"type":"paragraph","text":"        ];","spans":[]},{"type":"paragraph","text":"    });","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"heading4","text":"Seeder","spans":[]},{"type":"paragraph","text":"Now we need to define a seeder that will be run upon migrating the database. Start by generating the file:","spans":[]},{"type":"paragraph","text":"    ```[php]{`php artisan make:seeder ContactsTableSeeder`}```","spans":[]},{"type":"paragraph","text":"Open the generated file ```[php]{`database/seeds/ContactsTableSeeder.php`}``` in an editor and call the factory inside the ```[php]{`run()`}``` function like so:","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    <?php","spans":[]},{"type":"paragraph","text":"    use Illuminate\\Database\\Seeder;","spans":[]},{"type":"paragraph","text":"    class ContactsTableSeeder extends Seeder","spans":[]},{"type":"paragraph","text":"    {","spans":[]},{"type":"paragraph","text":"        /**","spans":[]},{"type":"paragraph","text":"         * Run the database seeds.","spans":[]},{"type":"paragraph","text":"         *","spans":[]},{"type":"paragraph","text":"         * @return void","spans":[]},{"type":"paragraph","text":"         */","spans":[]},{"type":"paragraph","text":"        public function run()","spans":[]},{"type":"paragraph","text":"        {","spans":[]},{"type":"paragraph","text":"            factory(App\\Contact::class, 10)->create();","spans":[]},{"type":"paragraph","text":"        }","spans":[]},{"type":"paragraph","text":"    }","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"paragraph","text":"To enable the seeder, edit `database/seeds/DatabaseSeeder.php` and call it inside the `run()` function:","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    <?php","spans":[]},{"type":"paragraph","text":"    use Illuminate\\Database\\Seeder;","spans":[]},{"type":"paragraph","text":"    class DatabaseSeeder extends Seeder","spans":[]},{"type":"paragraph","text":"    {","spans":[]},{"type":"paragraph","text":"        /**","spans":[]},{"type":"paragraph","text":"         * Seed the application's database.","spans":[]},{"type":"paragraph","text":"         *","spans":[]},{"type":"paragraph","text":"         * @return void","spans":[]},{"type":"paragraph","text":"         */","spans":[]},{"type":"paragraph","text":"        public function run()","spans":[]},{"type":"paragraph","text":"        {","spans":[]},{"type":"paragraph","text":"            $this->call(ContactsTableSeeder::class);","spans":[]},{"type":"paragraph","text":"        }","spans":[]},{"type":"paragraph","text":"    }","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"heading3","text":"Model","spans":[]},{"type":"paragraph","text":"There is one final adjustment that we need to make to the model. The ```[php]{`artisan make:model`}``` command generated a model file for us, located in ```[php]{`app/Contact.php`}```. The `favorites` column represents a JSON object, so we need to cast it to a PHP array before using it. Eloquent makes this very easy by automatically casting back and forth between the correct formats. Inside the ```[php]{`Contact`}``` class in ```[php]{`app/Contact.php`}```, we can add the cast:","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    <?php","spans":[]},{"type":"paragraph","text":"    namespace App;","spans":[]},{"type":"paragraph","text":"    use Illuminate\\Database\\Eloquent\\Model;","spans":[]},{"type":"paragraph","text":"    class Contact extends Model","spans":[]},{"type":"paragraph","text":"    {","spans":[]},{"type":"paragraph","text":"        protected $casts = [","spans":[]},{"type":"paragraph","text":"            'favorites' => 'array',","spans":[]},{"type":"paragraph","text":"        ];","spans":[]},{"type":"paragraph","text":"    }","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"heading2","text":"Step 3: Configure the Database","spans":[]},{"type":"paragraph","text":"We will use DigitalOcean Databases for our PostgreSQL cluster. If you haven’t yet, create a new one—it only takes a few minutes. If you prefer a text post, see the product documentation for Databases. If you prefer a video, click here.","spans":[{"start":160,"end":199,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/docs/databases/how-to/clusters/create/"}},{"start":224,"end":234,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.youtube.com/watch?v=jY5FhyiEdig"}}]},{"type":"image","url":"https://images.prismic.io/www-static/e80ddc5c-b52d-42a0-a6b9-faf3e0a10a51_Kamal-3.png?auto=compress,format","alt":null,"copyright":null,"dimensions":{"width":1600,"height":427}},{"type":"paragraph","text":"In the cluster’s Overview page in the control panel, get its connection details as “Connection parameters”. Open Laravel's ```[php]{`.env`}``` file and set ```[php]{`DB_CONNECTION=pgsql`}```. Below it, set all the other variables according to your connection credentials.","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/3f4ec974-28d2-46ca-80b3-18a8461abca2_Kamal-4.png?auto=compress,format","alt":null,"copyright":null,"dimensions":{"width":990,"height":540}},{"type":"paragraph","text":"There is one setting that isn’t available as an environment variable: ```[php]{`sslmode`}```. DigitalOcean Databases do not support non-TLS connections so we need to set ```[php]{`sslmode`}``` to ```[php]{`require`}```. Open ```[php]{`config/database.php`}``` in an editor, scroll down to the ```[php]{`pgsql`}``` definition, and update the setting like so:","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    'pgsql' => [","spans":[]},{"type":"paragraph","text":"        ...","spans":[]},{"type":"paragraph","text":"        'sslmode' => 'require',","spans":[]},{"type":"paragraph","text":"    ],","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"paragraph","text":"[Related: Check out our Resource Center for resources and guides on Managed Databases]","spans":[{"start":0,"end":86,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/resources/managed-databases/"}}]},{"type":"heading2","text":"Step 4: Migrate and seed","spans":[]},{"type":"paragraph","text":"Now that we have completed defining everything database-related in our app, from the Contact model to the database connection info, we can execute the migration and seed the database:","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    php artisan migrate --seed","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"paragraph","text":"We have a database filled with contacts now—nice!  ","spans":[]},{"type":"heading2","text":"Step 4: Build the Contact List Page","spans":[]},{"type":"paragraph","text":"Ok, let's finish up by creating a page to show our contacts.","spans":[]},{"type":"paragraph","text":"To keep things simple we will replace Laravel's default home page. Edit `routes/web.php` and set the `/` route to the following:","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    Route::get('/', function () {","spans":[]},{"type":"paragraph","text":"        $contacts = App\\Contact::all();","spans":[]},{"type":"paragraph","text":"        return view('welcome', ['contacts' => $contacts]);","spans":[]},{"type":"paragraph","text":"    });","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"paragraph","text":"This will fetch all the contacts from the database and pass them to the ```[php]{`welcome`}``` view.","spans":[]},{"type":"paragraph","text":"Then, edit the view located in `resources/views/welcome.blade.php` and replace its contents with the following:","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    <!doctype html>","spans":[]},{"type":"paragraph","text":"    <html>","spans":[]},{"type":"paragraph","text":"        <head>","spans":[]},{"type":"paragraph","text":"            <meta charset=\"utf-8\">","spans":[]},{"type":"paragraph","text":"            <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">","spans":[]},{"type":"paragraph","text":"    ","spans":[]},{"type":"paragraph","text":"            <title>Contacts</title>","spans":[]},{"type":"paragraph","text":"            <link rel=\"stylesheet\" href=\"https://unpkg.com/tachyons@4.10.0/css/tachyons.min.css\"/>","spans":[]},{"type":"paragraph","text":"        </head>","spans":[]},{"type":"paragraph","text":"        <body>","spans":[]},{"type":"paragraph","text":"            <div class=\"mw6 center pa3 sans-serif\">","spans":[]},{"type":"paragraph","text":"                <h1 class=\"mb4\">Contacts</h1>","spans":[]},{"type":"paragraph","text":"    ","spans":[]},{"type":"paragraph","text":"                @foreach($contacts as $contact)","spans":[]},{"type":"paragraph","text":"                <div class=\"pa2 mb3 striped--near-white\">","spans":[]},{"type":"paragraph","text":"                    <header class=\"b mb2\">{{ $contact->name }}</header>","spans":[]},{"type":"paragraph","text":"                    <div class=\"pl2\">","spans":[]},{"type":"paragraph","text":"                        <p class=\"mb2\">{{ $contact->phone }}</p>","spans":[]},{"type":"paragraph","text":"                        <p class=\"pre mb3\">{{ $contact->address }}</p>","spans":[]},{"type":"paragraph","text":"                        <p class=\"mb2\"><span class=\"fw5\">Favorite colors:</span> {{ implode(', ', $contact->favorites['colors']) }}</p>","spans":[]},{"type":"paragraph","text":"                    </div>","spans":[]},{"type":"paragraph","text":"                </div>","spans":[]},{"type":"paragraph","text":"                @endforeach","spans":[]},{"type":"paragraph","text":"            </div>","spans":[]},{"type":"paragraph","text":"        </body>","spans":[]},{"type":"paragraph","text":"    </html>","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"heading2","text":"Step 5: Deploy","spans":[]},{"type":"paragraph","text":"We're all done! Let's go ahead and try out our app.","spans":[]},{"type":"paragraph","text":"Like before, we can use Laravel's built-in web server. Simply run ```[php]{`php artisan serve`}``` and browse to http://127.0.0.1:8000.","spans":[{"start":113,"end":134,"type":"hyperlink","data":{"link_type":"Web","url":"http://127.0.0.1:8000/"}}]},{"type":"heading3","text":"Deploy on a Droplet","spans":[]},{"type":"paragraph","text":"To deploy the app on a Droplet, follow the How To Deploy a Laravel Application with Nginx on Ubuntu 16.04 guide on the DigitalOcean community.","spans":[{"start":43,"end":105,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-deploy-a-laravel-application-with-nginx-on-ubuntu-16-04"}}]},{"type":"heading2","text":"Conclusion","spans":[]},{"type":"paragraph","text":"In this post, we went through building a simple contacts list step by step and explored a few concepts such as seeding the database with sample random data, using JSON-type database fields, and connecting to a managed PostgreSQL Database.","spans":[]},{"type":"paragraph","text":"Here are a few things you can do following this post, building on the app we created:","spans":[]},{"type":"list-item","text":"Add a favorite shape (square, circle, etc.) to one or more contacts and edit the view template to display it. Update the seeder to include a random shape at random, or for every contact.","spans":[]},{"type":"list-item","text":"Extract the route handler (in ```[php]{`web.php`}```) into its own controller. Use ```[php]{`artisan make:controller`}``` to create the controller file. Consult the Laravel documentation on controllers for more details.","spans":[]},{"type":"list-item","text":"List the contacts in the order that they were last updated, most recent first.","spans":[]},{"type":"paragraph","text":"[Hungry for another tutorial? Try Kamal's guide to \"Deploying a Fully-automated Git-based Static Website in Under 5 Minutes\"]","spans":[{"start":0,"end":125,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/deploying-a-fully-automated-git-based-static-website-in-under-5-minutes/"}}]},{"type":"paragraph","text":"Kamal Nasser is a Developer Advocate at DigitalOcean. He is also a Computer Science student with a passion for software engineering and avocados. You can find him on Twitter @kamaln7.","spans":[{"start":0,"end":183,"type":"em"},{"start":174,"end":182,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/kamaln7"}}]}],"blog_post_date":"2019-02-21","tags":[{"tag1":{"tag":"Developer Relations","_linkType":"Link.document","_meta":{"uid":"developer-relations"}}},{"tag1":{"tag":"Community","_linkType":"Link.document","_meta":{"uid":"community"}}}],"_meta":{"uid":"create-simple-contacts-laravel-postgresql"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"Community Team","author_image":null,"_meta":{"uid":"community_team"}},"blog_header_image":{"dimensions":{"width":1200,"height":600},"alt":"scuba divers on computers illustration","copyright":null,"url":"https://images.prismic.io/www-static/03fe1bea1594de6d547c1b8fefc433f980ef7fc6_pathwaystechnicalwriting-final.png?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Becoming a Technical Writer: The Paths 3 Engineers Took to their First Community Tutorial","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"Regular readers of DigitalOcean Community tutorials (like How To Secure Apache with Let's Encrypt on Ubuntu 18.04 or How To Spin Up a Hadoop Cluster with DigitalOcean Droplets) may have noticed that beyond setup instructions, tutorials often contain insights, tips, and pain points surfaced from real-world production scenarios. This is because many of them are written by DevOps engineers, sysadmins, and software developers eager to share solutions and workarounds to problems faced while rolling out software and systems on the job.","spans":[{"start":58,"end":113,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-ubuntu-18-04"}},{"start":117,"end":175,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-spin-up-a-hadoop-cluster-with-digitalocean-droplets"}}]},{"type":"paragraph","text":"Through tutorials, DigitalOcean writers contribute their in-the-trenches experience to the wider developer community, and in doing so solidify their own understanding of technical concepts. Some authors work full-time on the DigitalOcean Community writing team, while others contribute tutorials as part of the Write for DOnations program, which matches the author's payout with a charitable donation to a tech-focused nonprofit. All Community contributors share a common spirit of “giving back” to readers through teaching, whether these readers are seasoned engineering managers, or students wading in the waters of setting up an Nginx server or Jupyter Notebook for the first time.","spans":[{"start":311,"end":330,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/write-for-donations/"}},{"start":618,"end":644,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-18-04"}},{"start":648,"end":664,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-set-up-jupyter-notebook-for-python-3"}}]},{"type":"paragraph","text":"DigitalOcean tutorials can broadly be categorized as either conceptual or procedural. An Introduction to Kubernetes, for example, is more conceptual in nature, as the author provides the reader with an overview of a piece of software or DevOps concept and boils it down to a set of digestible core ideas. How To Set Up an Elasticsearch, Fluentd, and Kibana (EFK) Logging Stack on Kubernetes, on the other hand, is a procedural walkthrough to support a developer setting up their infrastructure. The tutorial brings the reader through the installation and configuration of one or several technologies step-by-step, often providing valuable insight and context along the way.","spans":[{"start":86,"end":115,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/an-introduction-to-kubernetes"}},{"start":305,"end":390,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-set-up-an-elasticsearch-fluentd-and-kibana-efk-logging-stack-on-kubernetes"}}]},{"type":"heading3","text":"Becoming a Technical Writer","spans":[]},{"type":"paragraph","text":"There is no “one” path to becoming a DigitalOcean tutorial writer. Mitchell Anicas, formerly a senior technical writer on the Community team, and now a senior software engineer on the Billing team, began his career as a systems administrator at the University of Hawaii. After relocating to New York, he leveraged his years of experience administering systems and automating their configuration and deployment to begin writing Linux and infrastructure tutorials full-time.","spans":[{"start":67,"end":82,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/users/manicas"}}]},{"type":"paragraph","text":"“While working as a sysadmin, many of the tutorials I referenced weren’t complete, or weren’t really that high quality. It was a lot of someone writing blog posts saying something like ‘this is how this worked for me,’” he says. “Since I had been on the other side, I had a lot of empathy for readers.” Although he’d never written a tutorial before, with the help of other Community writers (all tutorials are peer-edited and tech-tested by another member of the Community team), he began publishing articles like How To Install Elasticsearch, Logstash, and Kibana (ELK Stack) on Ubuntu 14.04 and 5 Common Server Setups For Your Web Application.","spans":[{"start":514,"end":592,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-install-elasticsearch-logstash-and-kibana-elk-stack-on-ubuntu-14-04"}},{"start":597,"end":644,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/5-common-server-setups-for-your-web-application"}}]},{"type":"paragraph","text":"On the other hand, Erika Heidi, a software engineer and writer based out of Amsterdam, had always been a writer. “I’ve always enjoyed writing, since I was very young,” she says. “I figured out that I could use blogging as a platform for documenting technical things like setting up servers and fixing common Linux problems, both as a future reference for myself and also as a way to share what I was learning.”","spans":[{"start":19,"end":30,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/users/erikaheidi"}}]},{"type":"paragraph","text":"As a Community author, she’s contributed many tutorials, ranging from the procedural How To Secure Apache with Let's Encrypt on Ubuntu 16.04, to conceptual articles like What is High Availability and An Introduction to Configuration Management that draw from her extensive experience as a DevOps engineer. Like Mitchell, her technical experience endowed her with a keen sense for the problems her peers were facing and solutions she could provide to fill the gap.","spans":[{"start":85,"end":140,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-ubuntu-16-04"}},{"start":170,"end":195,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/what-is-high-availability"}},{"start":200,"end":243,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/an-introduction-to-configuration-management"}}]},{"type":"paragraph","text":"Jeremy Morris followed a similar path to publishing his first DigitalOcean tutorial: “Throughout college as a computer science student, I would occasionally write blog posts about some of the things I learned at my internships, as a way of gaining a deeper understanding of the topics and sharing my knowledge with others,” he recalls. One of his professors, Lisa Tagliaferri, now managing the team of in-house Community writers at DigitalOcean, recommended he leverage his newly gained Python and Django experience and write a tutorial series on building a blog. This eventually led to him publishing Django tutorials like How To Install Django and Set Up a Development Environment on Ubuntu 16.04, How To Create a Django App and Connect it to a Database and How To Create Django Models, all topics he had become familiar with through his professional work.","spans":[{"start":0,"end":13,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/users/jeremylevanmorris"}},{"start":624,"end":698,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-install-django-and-set-up-a-development-environment-on-ubuntu-16-04"}},{"start":700,"end":755,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-create-a-django-app-and-connect-it-to-a-database"}},{"start":760,"end":787,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-create-django-models"}}]},{"type":"paragraph","text":"Mitchell, Erika, and Jeremy all became writers at different stages of their careers in tech. Their common desire to help their peers through sharing hard-won solutions to challenging DevOps problems led them to publish their first DigitalOcean tutorials. While writing and educating others presented them with the need to develop distinct communication skills, they found that the challenge of describing solutions in a clear and accessible manner was well worth developing alongside their engineering experience.","spans":[]},{"type":"heading3","text":"Why Write?","spans":[]},{"type":"paragraph","text":"Technical writing can be a powerful complement to engineering work, requiring the author to understand and process concepts at a deeper level than may be required to complete day-to-day tasks. Erika, in her drive to deeply understand the technologies she works with as a DevOps engineer, finds that writing tutorials helps her truly gain familiarity with new ideas: “There’s a lot of stuff in engineering I know how to do because I’ve done it multiple times before and it simply works, but if I had to explain how it works, I couldn’t,” she notes. “Writing helps me ‘untangle’ my thoughts, because I have to explain and organize those thoughts into logical steps.”","spans":[]},{"type":"paragraph","text":"It can also be an incredibly rewarding pursuit. By publishing open-source tech tutorials, Erika feels that she is helping others who have similarly lent a hand throughout her learning path: “I believe the fulfillment comes from the feeling that I’m sharing something that might be useful for others. I’m searching for tutorials and how to do stuff all the time on the internet, and this is one way I can give back to the community.”","spans":[]},{"type":"paragraph","text":"Mitchell shares this sense of being able to contribute his experience and knowledge through tutorials: “It’s cool to be able to help thousands of people through writing, especially writing tutorials for DigitalOcean, whose tutorials are respected and recognized by the developer community at large. I’ll be at a conference and run into someone and they’ll say something like ‘Oh yeah I used that tutorial of yours to set up an ELK stack, thanks so much!’”","spans":[]},{"type":"heading3","text":"Taking the Plunge and Diving into the Technical Writing","spans":[]},{"type":"paragraph","text":"So how do you get started writing your first DevOps, software development, or systems tutorial? By jumping into the deep end, of course! Through the Write for DOnations program you can submit a short writing sample (for inspiration, take a look at this list of suggested topics) and work with our Community editors to have your article edited, tech-tested, proofread, and guided to publication. In addition, you'll be paid for your work, and DigitalOcean will match your payout with a donation to a tech-focused charity of your choice. To date, DigitalOcean has donated over $13,000 through external-author submissions and the Write for DOnations program!","spans":[{"start":149,"end":168,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/write-for-donations/"}},{"start":248,"end":257,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/suggested-topics-for-tutorials"}},{"start":499,"end":519,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/write-for-donations-faq#which-charities-and-nonprofits-will-my-writing-support"}}]},{"type":"paragraph","text":"In addition, the Community team frequently has openings for new writers, editors, and developer advocates to educate, curate, and produce some of the highest quality software-focused tutorials on the web. If you’re a DevOps or software engineer and have some experience writing documentation or other content, consult our Careers page for an up-to-date list of open full-time Community positions.","spans":[{"start":322,"end":329,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/careers/"}}]},{"type":"paragraph","text":"Although he may have been referring to something other than the pains of backing up and replicating a large distributed MySQL database, let Hemingway’s words guide you as you set sail on your technical writing voyage: “write hard and clear about what hurts.”","spans":[]}],"blog_post_date":"2019-02-19","tags":[{"tag1":{"tag":"Community","_linkType":"Link.document","_meta":{"uid":"community"}}}],"_meta":{"uid":"how-three-engineers-wrote-their-first-community-tutorials"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"André Bearfield","author_image":{"dimensions":{"width":553,"height":547},"alt":"André Bearfield","copyright":null,"url":"https://images.prismic.io/www-static/fdc7c85186f0a850b04083e1d4306bd1c19772e8_andre-bearfield.png?auto=compress,format"},"_meta":{"uid":"andre-bearfield"}},"blog_header_image":{"dimensions":{"width":1024,"height":512},"alt":"managed databases graphic","copyright":null,"url":"https://images.prismic.io/www-static/be19c7304455e3f67f95135b99df558bfb175297_dbaas_digitalocean_blog.jpg?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Our Valentine’s Gift to You: Managed Databases for PostgreSQL","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"If you’re building a modern application, chances are you’ll need to store data in some persistent state. Over the last few years, we’ve been building features to help – providing Droplets with generous SSD storage and adding Block Storage as another flexible option for you to maintain stateful applications. These features have enabled you to build your entire application stack, including your own databases, on our platform.","spans":[]},{"type":"paragraph","text":"However, you’re probably aware that building and maintaining your own database cluster can be cumbersome and can take away time from solving your business problems or application logic. That’s why our community has been asking for more automation and management of databases in order to focus on what's important: writing code.","spans":[]},{"type":"paragraph","text":"Well, today we are excited to bring you Managed Databases by DigitalOcean, our own fully managed and feature rich database service. Starting with support for PostgreSQL, Managed Databases enables developers of all skill levels to quickly and easily spin up a high-performance database cluster that is worry-free and scalable. Best of all, you don’t need to know anything about the Linux operating system or specific DevOps maintenance tasks.","spans":[{"start":40,"end":57,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/managed-databases"}}]},{"type":"paragraph","text":"Managed Databases takes care of the common challenges that many businesses and developers face when building a database cluster from the ground up:","spans":[]},{"type":"list-item","text":"Identifying the optimal database infrastructure footprint","spans":[]},{"type":"list-item","text":"Scaling infrastructure as business and data requirements grow","spans":[]},{"type":"list-item","text":"Designing and managing highly available infrastructure and failover processes","spans":[]},{"type":"list-item","text":"Implementing a complete and reliable backup and recovery strategy","spans":[]},{"type":"list-item","text":"Forecasting and maintaining operational infrastructure costs","spans":[]},{"type":"heading3","text":"How it Works","spans":[]},{"type":"paragraph","text":"Managed Databases provides a stable endpoint that developers can throw data into and request data from, so you don’t have to think about the intricacies of database administration.","spans":[]},{"type":"paragraph","text":"We’re leading with PostgreSQL 10 and 11, which has more than 30 years of active community development. This makes it the most advanced SQL-compliant object-relational database on the market. Since it’s built on top of our core compute platform and uses local SSD storage, it’s lightning fast. In addition to our simple database dashboard, you can manage your database clusters programmatically with the DigitalOcean API.","spans":[{"start":403,"end":419,"type":"hyperlink","data":{"link_type":"Web","url":"https://developers.digitalocean.com/documentation/v2/#databases"}}]},{"type":"paragraph","text":"You can configure your database to be accessed from anywhere in the world, but, as you probably guessed, you will get higher performance if your data is near your application server. Therefore, we’ve enabled the service in all of our available regions, although some data center exceptions do exist.","spans":[{"start":267,"end":289,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/docs/platform/availability-matrix/"}}]},{"type":"paragraph","text":"You’ll enjoy simple, predictable pricing that allows you to control your costs. Spin up a database node starting from $15 per month or high availability cluster from $50 per month. Backups are included for free with your service to keep things simple. Ingress bandwidth is always free, and egress fees ($0.01/GB per month) will be waived for 2019.","spans":[{"start":13,"end":40,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/pricing/#anchor--Databases"}}]},{"type":"paragraph","text":"Check out a demo of Managed Databases in action!","spans":[]},{"type":"heading3","text":"The Benefits of Managed Databases","spans":[]},{"type":"heading4","text":"Worry-free database maintenance","spans":[]},{"type":"paragraph","text":"A significant advantage to Managed Databases is saving time – lots of time. Quickly deploy a database, and we’ll handle the rest. Never worry again about security patches to the OS or database engine – once a new version or patch is available, simply click a button to enable it.","spans":[]},{"type":"heading4","text":"Highly secure and optimized for performance","spans":[]},{"type":"paragraph","text":"All data is encrypted at rest and in transit. Use the Cloud Firewall to restrict connections to your database. Your database runs on enterprise-class VM hardware with local SSD storage, giving you lightning-fast performance.","spans":[]},{"type":"heading4","text":"Easy scalability","spans":[]},{"type":"paragraph","text":"The “right size” for your infrastructure is a moving target. With Managed Databases, you can scale up at anytime with virtually no impact to your application. You have flexibility, so you can spin up read-only nodes to scale read operations or remove compute overhead from reporting requirements.","spans":[]},{"type":"heading4","text":"Automatic failovers","spans":[]},{"type":"paragraph","text":"Sleep easy, knowing that if an issue occurs with your primary node, traffic will automatically get routed to your standby nodes. We recommend selecting a high-availability option to minimize the impact in case of a failure.","spans":[]},{"type":"heading4","text":"Simple and reliable backup and recovery solution","spans":[]},{"type":"paragraph","text":"Backups are handled automatically and included to you at no additional fee. Full backups are taken everyday and write-ahead-logs are maintained to allow you to restore to any point-in-time during the retention period.","spans":[]},{"type":"paragraph","text":"[Related: Check out our Resource Center for resources and guides on Managed Databases]","spans":[{"start":0,"end":86,"type":"strong"},{"start":0,"end":86,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/resources/managed-databases/"}}]},{"type":"heading3","text":"What’s Next","spans":[]},{"type":"paragraph","text":"We hope you are as excited as we are about this release! Our engineering team is working hard to bring you even more functionality for your databases in 2019.  We plan to have additional engines such as Redis and MySQL, private networking with enhanced VPC, metrics, and alerting through Insights.","spans":[]},{"type":"paragraph","text":"If you are planning to attend Postgres Conference in New York City March 18–22, be sure to stop by and chat with me and the other members of the Product team. We’d love to meet you.","spans":[{"start":30,"end":49,"type":"hyperlink","data":{"link_type":"Web","url":"https://postgresconf.org/conferences/2019"}}]},{"type":"paragraph","text":"Ready to create a database? Try Managed Databases now.","spans":[{"start":0,"end":54,"type":"hyperlink","data":{"link_type":"Web","url":"http://cloud.digitalocean.com/databases"}}]},{"type":"paragraph","text":"Happy Coding,","spans":[]},{"type":"paragraph","text":"André Bearfield","spans":[]},{"type":"paragraph","text":"Sr. Product Manager","spans":[]}],"blog_post_date":"2019-02-14","tags":[{"tag1":{"tag":"Product Updates","_linkType":"Link.document","_meta":{"uid":"product-updates"}}}],"_meta":{"uid":"announcing-managed-databases-for-postgresql"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"Shiven Ramji","author_image":{"dimensions":{"width":170,"height":170},"alt":"Shiven Ramji","copyright":null,"url":"https://images.prismic.io/www-static/79c5726c75adb45644613d2371026b1bb789a415_shiven_ramji-090ac31e.png?auto=compress,format"},"_meta":{"uid":"shiven_ramji"}},"blog_header_image":{"dimensions":{"width":1569,"height":837},"alt":"2019 illustration","copyright":null,"url":"https://images.prismic.io/www-static/1248f67cc67178c72f71ba51abadd6afb4a6ba44_2019_yearinreview_social_blog.png?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"2019: What's Coming Next On DigitalOcean","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"It is the beginning of the year and an opportunity for us to reflect on 2018 and share what’s upcoming for our community in 2019.","spans":[]},{"type":"paragraph","text":"Last year, we shared details on the progress we’ve made on an ambitious roadmap in January and August. Here’s a recap:","spans":[{"start":83,"end":90,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/2018-whats-shipping-next-on-digitalocean/"}},{"start":95,"end":101,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/2018-mid-year-product-update/"}}]},{"type":"list-item","text":"We kicked off 2018 with new Droplet plans that got even better with pooled bandwidth billing so that you can share your bandwidth allocations across all Droplets in your account and make it less likely that you will incur overage bandwidth charges.","spans":[{"start":24,"end":41,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/new-droplet-plans/"}}]},{"type":"list-item","text":"One of the areas we always look to improve is the developer experience, including how you manage your DigitalOcean service through our UI or our API.  In March, we released a new Control Panel Dashboard, making it faster to access common resources and account information, as well as changes to the navigation with quick links to API and community documentation.","spans":[{"start":179,"end":202,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/introducing-control-panel-dashboard/"}}]},{"type":"list-item","text":"In May, we updated our Load Balancers product, making it easier to deliver HTTPS using Let’s Encrypt with an automated integration and we added support for HTTP/2 to improve performance and security.  We also lowered the pricing of Load Balancers by 50%, down to $10/mo.","spans":[{"start":11,"end":45,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/introducing-load-balancer-upgrades/"}},{"start":87,"end":100,"type":"hyperlink","data":{"link_type":"Web","url":"https://letsencrypt.org/"}}]},{"type":"list-item","text":"In June, we released a new DigitalOcean Product Documentation center, which contains overviews and quickstart guides on everything DigitalOcean has to offer, as well as How-Tos and Resource links to dive in deeper.","spans":[{"start":40,"end":61,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/docs/"}}]},{"type":"list-item","text":"In August, we released Projects, a new way to control and organize your infrastructure on DigitalOcean.  These changes are designed to save you time, and make it easier to access the most important information as your infrastructure grows.","spans":[{"start":23,"end":31,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/organizing-your-infrastructure-with-projects/"}}]},{"type":"list-item","text":"In September we released a built-in CDN with Spaces with no additional costs. With this new capability, your Spaces content gets delivered much faster to end users from global edge locations around the world.","spans":[{"start":16,"end":51,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/spaces-now-includes-cdn/"}}]},{"type":"list-item","text":"Also in September, we added support for Custom Images so that you can bring your own environment to DigitalOcean and spin up Droplets using your own customized operating system.","spans":[{"start":40,"end":53,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/custom-images/"}}]},{"type":"list-item","text":"As many developers want to automate their creation and management of infrastructure using tools like Terraform, in October, we released version 1.0.0 of the DigitalOcean Terraform provider.  We worked with the community to build support into the Terraform provider for all of the resources you typically use on DigitalOcean, now available as Terraform resources.","spans":[{"start":136,"end":188,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/introducing-the-digitalocean-terraform-provider/"}}]},{"type":"list-item","text":"We launched a managed Kubernetes beta in May, and made DigitalOcean Kubernetes available to all users in December.  Kubernetes has become the standard for deploying containers to production, and well over 30,000 developers have used DigitalOcean Kubernetes to learn about Kubernetes and deploy container workloads.","spans":[{"start":33,"end":44,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/introducing-digitalocean-kubernetes/"}},{"start":55,"end":113,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/introducing-digitalocean-kubernetes/"}}]},{"type":"heading1","text":"What’s coming in 2019","spans":[]},{"type":"paragraph","text":"Our Product and Engineering teams are focused on making the experience you love on DigitalOcean even better. We are focused on providing services that take away the operational burden from you so that small teams can continue to focus on what’s important for their business and worry less about the underlying infrastructure. We are also improving all of the tooling and integrations required to quickly deploy your applications to the cloud. This includes continuous improvements to the Control Panel, API, CLI, and supporting features such as Tags, Teams, and Projects.","spans":[]},{"type":"heading2","text":"Managed Databases","spans":[]},{"type":"paragraph","text":"Late last year we opened up beta sign-ups for a new service that makes it easy to host your databases on DigitalOcean as a managed service. We are starting with supporting Postgres database engine and plan to release MySQL and Redis later in the year.  We’ll share additional details in the coming weeks.","spans":[]},{"type":"heading2","text":"Application Marketplace","spans":[]},{"type":"paragraph","text":"Our one-click applications have made it easy for many of you to launch your applications in the cloud. However, we believe we can improve the experience of getting started quickly by removing the complexity of installing and configuring common application building blocks and dependencies, such as development stacks, solutions, and services. In 2019, we plan to launch a curated Marketplace that will bring vendor applications and solutions to the large community that we have and give you even more choice in the solutions you need to get your business up and running. We’ll share additional details in the coming weeks.","spans":[]},{"type":"heading2","text":"Kubernetes","spans":[]},{"type":"paragraph","text":"We are adding many new features to our Managed Kubernetes (DOKS) product, and plan to bring new cluster metrics, token-based authentication, a container registry, autoscaling, role-based access control support integration, support for deploying and managing workloads and other resources via the DigitalOcean UI, and the ability to upgrade your Kubernetes version automatically over the course of this year.","spans":[]},{"type":"heading2","text":"New Droplet Types","spans":[]},{"type":"paragraph","text":"When we rolled out our CPU Optimized Droplets, we found that many users needed the consistently high performance of dedicated CPU resources.  Our users have since asked for similar plans with higher memory options, and we’re working on providing high memory Droplets with dedicated CPUs. A new line of Performance Droplets called General Purpose Droplets will be in Limited Availability starting Q1.","spans":[]},{"type":"heading2","text":"Spaces","spans":[]},{"type":"paragraph","text":"We will launch Spaces in Frankfurt earlier in the year and London subsequently, extending choice for users deploying applications globally. We will also add SSL Certificate support to the built-in Spaces CDN endpoints and subdomain support streamlining the process of deploying websites.","spans":[]},{"type":"heading2","text":"Developer Experience","spans":[]},{"type":"paragraph","text":"As always, we’re focused on bringing the best possible experience to our customers. This year we’ll be adding project and tags support for all of our new products, as well as improving monitoring and insights across the portfolio. In addition, we’ll make it easier to create and manage your team at DigitalOcean.","spans":[]},{"type":"heading1","text":"Give Us Your Feedback","spans":[]},{"type":"paragraph","text":"We have been busy building towards our vision of making it easier for developers to build modern applications.  This is only a sampling of all the features and improvements we are planning for 2019. We hope they are lining up with the kinds of services you need, and we really want to hear from you on any ideas for what you’d like to see next!  Please share your thoughts with us in the comments below.","spans":[]},{"type":"paragraph","text":"Happy coding,","spans":[]},{"type":"paragraph","text":"Shiv, VP Product","spans":[]}],"blog_post_date":"2019-01-31","tags":[{"tag1":{"tag":"Product Updates","_linkType":"Link.document","_meta":{"uid":"product-updates"}}}],"_meta":{"uid":"whats-new-for-2019"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"Community Team","author_image":null,"_meta":{"uid":"community_team"}},"blog_header_image":{"dimensions":{"width":799,"height":433},"alt":"People on a boat illustration","copyright":null,"url":"https://images.prismic.io/www-static/fba651e193b42ae8b36a402a7e5daa04949d87e6_dribbble_boat-1.png?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Here's A Round-Up of 2018 Community Tutorials","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"2018 has been an exciting year for us on the DigitalOcean Community team as we surpassed over 2,000 tutorials in our repository in September!","spans":[{"start":94,"end":109,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials"}}]},{"type":"paragraph","text":"We continue to work with community authors to publish tutorials that serve developers. In February of this year we launched our Write for DOnations program, which not only adds to our Community knowledge base, but also gives back through making a donation to tech-focused nonprofits. If you are thinking about sharing your knowledge with the developer community, consider applying to this program so you can begin working with Community Editors who will offer you mentorship as you write your tutorial.","spans":[{"start":128,"end":147,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/write-for-donations/"}},{"start":259,"end":282,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/write-for-donations-faq#which-charities-and-nonprofits-will-my-writing-support"}},{"start":372,"end":396,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/write-for-donations/#anchor--apply-now"}}]},{"type":"paragraph","text":"This year, we also released new learning resources. DigitalOcean Blueprints offer automated multi-server infrastructure setups to support you as you scale. Our first Community white paper, Running Cloud Native Applications on DigitalOcean Kubernetes, provides guidance for you and your team as you get up and running with Kubernetes.","spans":[{"start":52,"end":75,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/digitalocean-blueprints-getting-up-and-running-with-node-js-mysql-replication-and-cachet"}},{"start":189,"end":249,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/white-paper-running-cloud-native-applications-on-digitalocean-kubernetes"}}]},{"type":"paragraph","text":"Additionally, we have begun to offer tutorials to help you with automating your server setups, and have worked to keep tutorials up-to-date through maintenance, with pushes for both the Ubuntu 18.04 and Debian 9 updates.","spans":[{"start":64,"end":93,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/automating-initial-server-setup-with-ubuntu-18-04"}}]},{"type":"paragraph","text":"We selected a few tutorials below that showcase some of the breadth and depth that we and our community wrote about this year: from building neural networks to architecting applications for Kubernetes.","spans":[]},{"type":"list-item","text":"Modernizing Applications for Kubernetes","spans":[{"start":0,"end":39,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/modernizing-applications-for-kubernetes"}}]},{"type":"list-item","text":"In this conceptual guide by Hanif Jetha, learn about the high-level steps you need to follow for modernizing your applications so that you can ultimately run and manage them in a Kubernetes cluster.","spans":[]},{"type":"list-item","text":"How To Build a Modern Web Application to Manage Customer Information with Django and React on Ubuntu 18.04","spans":[{"start":0,"end":106,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-build-a-modern-web-application-to-manage-customer-information-with-django-and-react-on-ubuntu-18-04"}}]},{"type":"list-item","text":"Build a modern web application with a separate REST API backend and frontend using React, Django, and the Django REST Framework by going through this tutorial by Ahmed Bouchefra.","spans":[]},{"type":"list-item","text":"How To Build a Neural Network to Recognize Handwritten Digits with TensorFlow","spans":[{"start":0,"end":77,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-build-a-neural-network-to-recognize-handwritten-digits-with-tensorflow"}}]},{"type":"list-item","text":"Neural networks, used as a method of deep learning, attempt to simulate the way the human brain works. This tutorial by Ellie Birbeck will walk you through implementing a subsection of object recognition by using TensorFlow, an open-source Python library.","spans":[]},{"type":"list-item","text":"How To Manage an SQL Database","spans":[{"start":0,"end":29,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-manage-sql-database-cheat-sheet"}}]},{"type":"list-item","text":"For anyone who has ever desired a quick reference to some of the most commonly-used SQL commands, Mark Drake delivers in this cheat sheet tutorial.","spans":[]},{"type":"list-item","text":"Kubernetes Networking Under the Hood","spans":[{"start":0,"end":36,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/kubernetes-networking-under-the-hood"}}]},{"type":"list-item","text":"Brian Boucheron breaks down how Kubernetes networking works within a cluster, including how data moves inside a pod, between pods, and between nodes.","spans":[]},{"type":"list-item","text":"How To Use Alertmanager And Blackbox Exporter To Monitor Your Web Server On Ubuntu 16.04","spans":[{"start":0,"end":88,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-use-alertmanager-and-blackbox-exporter-to-monitor-your-web-server-on-ubuntu-16-04"}}]},{"type":"list-item","text":"Sending alerts when problems arise significantly speeds up identifying the root cause of an issue and helps you recover quickly. Marko Mudrinić’s tutorial covers Alertmanager and Blackbox Exporter to monitor the responsiveness of an Nginx web server, allowing you to send e-mail and Slack notifications if your server isn't responding.","spans":[]},{"type":"list-item","text":"DigitalOcean eBook: How To Code in Python","spans":[{"start":0,"end":41,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/digitalocean-ebook-how-to-code-in-python"}}]},{"type":"list-item","text":"Not quite a single tutorial, but our free eBook that collects together Lisa Tagliaferri’s more than 30 Python tutorials so you can learn how to code in Python or reference Python syntax while you’re on the go.","spans":[]},{"type":"list-item","text":"How to Use Traefik as a Reverse Proxy for Docker Containers on Ubuntu 18.04","spans":[{"start":0,"end":75,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-use-traefik-as-a-reverse-proxy-for-docker-containers-on-ubuntu-18-04"}}]},{"type":"list-item","text":"When you are trying to run multiple applications on the same host, you’ll need to set up a reverse proxy. Traefik is a Docker-aware reverse proxy solution offering its own monitoring dashboard. Learn how to use Traefik to route requests to two different web application containers by following this tutorial by Keith Thompson.","spans":[]},{"type":"list-item","text":"How to Automatically Deploy Laravel Applications with Deployer on Ubuntu 16.04","spans":[{"start":0,"end":78,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/automatically-deploy-laravel-applications-deployer-ubuntu"}}]},{"type":"list-item","text":"Laravel is an open-source PHP web framework designed to make common web development tasks easier. András Magyar walks you through deploying a Laravel application automatically without any downtime.","spans":[]},{"type":"list-item","text":"How To Build a Node.js Application with Docker","spans":[{"start":0,"end":46,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-build-a-node-js-application-with-docker"}}]},{"type":"list-item","text":"Recreate and scale your Node.js application with Docker by following this tutorial by Kathleen Juell.","spans":[]},{"type":"list-item","text":"How to Deploy a Symfony 4 Application to Production with LEMP on Ubuntu 18.04","spans":[{"start":0,"end":77,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/how-to-deploy-a-symfony-4-application-to-production-with-lemp-on-ubuntu-18-04"}}]},{"type":"list-item","text":"Deploy a Symfony 4 application to production with a LEMP stack on Ubuntu 18.04 to get started configuring the server and the structure of the framework. Oluyemi Olususi’s tutorial will take you through all the steps you need.","spans":[]},{"type":"list-item","text":"Architecting Applications for Kubernetes","spans":[{"start":0,"end":40,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tutorials/architecting-applications-for-kubernetes"}}]},{"type":"list-item","text":"Designing and running applications with scalability, portability, and robustness in mind can be challenging, especially as system complexity grows. In Justin Ellingwood’s guide, learn some of the principles and patterns you can adopt to help you scale and manage your workloads on Kubernetes.","spans":[]}],"blog_post_date":"2018-12-20","tags":[{"tag1":{"tag":"Community","_linkType":"Link.document","_meta":{"uid":"community"}}}],"_meta":{"uid":"2018-community-tutorials-roundups"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"Phil Dougherty","author_image":{"dimensions":{"width":573,"height":557},"alt":"Phil Dougherty","copyright":null,"url":"https://images.prismic.io/www-static/ef89c36114b5e1872e8de0b79eb679b9be5b3765_phil.png?auto=compress,format"},"_meta":{"uid":"phil_dougherty"}},"blog_header_image":{"dimensions":{"width":1200,"height":640},"alt":"Kubernetes illustration","copyright":null,"url":"https://images.prismic.io/www-static/f0ae65520153925bcf7961cce341d2b1a61a293b_image8-1.png?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Managing Kubernetes Just Got a Lot Simpler","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"Today we are opening up DigitalOcean Kubernetesto everyone!  Over the last few months, we have been inspired to see more than 30,000 developers use our platform to learn Kubernetes and deploy web applications, microservices, CI/CD pipelines, IoT applications, blockchain-based services, CDNs, VPNs, and many types of APIs.","spans":[{"start":24,"end":47,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/kubernetes/"}},{"start":47,"end":59,"type":"strong"}]},{"type":"paragraph","text":"We designed DigitalOcean Kubernetes to be a powerfully simple managed Kubernetes service. All you need to do is define the size and location of your worker nodes while DigitalOcean provisions, manages, and optimizes the services needed to run your Kubernetes cluster. Setup takes just minutes, and we provide a Kubernetes endpoint that you can use with any tools you’d like, from the standard kubectl command line interface (CLI) to the rich and growing ecosystem of Kubernetes services.","spans":[]},{"type":"image","url":"https://images.prismic.io/www-static/YzZjMGQ0MjAtYzE3Mi00MjlkLWIyY2UtMmMyMTI4YmRlYWEx_k8s-control.gif?auto=compress,format","alt":"DigitalOcean Kubernetes Control Panel","copyright":null,"dimensions":{"width":629,"height":418}},{"type":"paragraph","text":"All DigitalOcean users will now find Kubernetes available on their Control Panel.  If you are new to the service, just enable yourself and walk through the guided configuration to choose the number, size, and location of your worker nodes. Once provisioned, download your cluster configuration file to use with the kubectl CLI, and start deploying your containerized applications.","spans":[]},{"type":"paragraph","text":"[Related: Explore all of DigitalOcean's Kubernetes resources, including tutorials, webinars, presentations, and product documentation]","spans":[{"start":1,"end":133,"type":"strong"},{"start":18,"end":60,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/resources/kubernetes/"}}]},{"type":"heading3","text":"What you can expect","spans":[]},{"type":"paragraph","text":"DigitalOcean Kubernetes is available using the latest version of Kubernetes, v1.12.3, and integrates with existing DigitalOcean products, including Block Storage and Load Balancers, so that you can reliably scale your persistent storage and incoming traffic. In addition we have just released support for DigitalOcean Kubernetes in the DigitalOcean API, making it easy to create and manage your clusters through our API.","spans":[{"start":336,"end":352,"type":"hyperlink","data":{"link_type":"Web","url":"https://developers.digitalocean.com/documentation/v2/#kubernetes"}}]},{"type":"paragraph","text":"One of the key benefits of Kubernetes is the ability to use resources more efficiently, packing containerized applications into worker nodes that have available capacity. This provides cost savings and enables developers to run applications with minimal unused resources.  We are making Kubernetes even more cost effective by providing the basic Kubernetes management services to our users at no additional cost.","spans":[]},{"type":"paragraph","text":"Pricing for DigitalOcean Kubernetes is based only on the underlying resources that you use (Droplets, Block Storage, and Load Balancers).  Each Kubernetes cluster now starts with two Droplets of your choice, with the same simple pricing available today for Droplets. You also have the option to add Block Storage at the standard rate of $0.10/GB per month, and Load Balancers at $10 per month.","spans":[{"start":299,"end":312,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/products/block-storage/"}},{"start":361,"end":375,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/introducing-load-balancer-upgrades/"}}]},{"type":"paragraph","text":"Since announcing DigitalOcean Kubernetes, we’ve listened to what our customers wanted most. With the May 2018 early access release, we focused on simplifying the most critical needs of developers when deploying Kubernetes containerized apps: node provisioning, durable storage availability, security, and scalability.","spans":[{"start":6,"end":40,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/introducing-digitalocean-kubernetes/"}}]},{"type":"paragraph","text":"This included:","spans":[]},{"type":"list-item","text":"Fully configured worker nodes based on any Droplet size","spans":[]},{"type":"list-item","text":"Seamless integration with flexible block storage; worker node protection with firewalls","spans":[]},{"type":"list-item","text":"Integration with Load Balancers for simple, robust, and secure app scaling, and","spans":[]},{"type":"list-item","text":"Implementation of continuous integration and continuous delivery workflows in a matter of seconds to further streamline the development process","spans":[]},{"type":"heading3","text":"Looking ahead","spans":[]},{"type":"paragraph","text":"Today’s announcement is a continuation of that journey. We have many more features coming to DigitalOcean Kubernetes and are working hard to bring a private and integrated container image registry, Kubernetes cluster metrics, new global regions, Role Based Access Control (RBAC) integration with Teams, Network Policy support, autoscaling, and automated Kubernetes version upgrades.  Stay tuned for more news in the coming weeks and months!","spans":[]},{"type":"paragraph","text":"Let us know your thoughts and any questions you have in the comments below. Also, if you’re attending KubeCon North America this week, December 10 to 13, in Seattle, please stop by and visit us.  We would love to meet you and show you a demo.  We are located in Hall 4AB on Level 4, Booth Number P10.","spans":[]},{"type":"paragraph","text":"In addition, two DigitalOcean engineers are speaking at KubeCon, covering specific cloud native topics. Please check out:","spans":[]},{"type":"list-item","text":"Andrew Kim’s talk, “Towards a Vendor Neutral Kubernetes,” on Tuesday, December 11 from 10:50 am - 11:25 am in Ballroom 6A.  Andrew is a co-chair of the SIG Cloud Provider and will dive into what the community has been doing to move towards a vendor-neutral model with sustainability and portability as a top priority.","spans":[{"start":0,"end":10,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.twitter.com/a_sykim"}},{"start":20,"end":55,"type":"hyperlink","data":{"link_type":"Web","url":"https://kccna18.sched.com/event/GrTl/towards-a-vendor-neutral-kubernetes-andrew-kim-digitalocean"}}]},{"type":"list-item","text":"Tim Simmons’s talk, “Adopting Prometheus The Hard Way,” on Wednesday, December 12 from 3:40 pm - 4:15 pm in Venue 606-609.  Tim will discuss learnings from scaling the adoption of Prometheus within your organization and the importance of fostering an Observability culture.","spans":[{"start":0,"end":11,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.twitter.com/timsimlol"}},{"start":21,"end":53,"type":"hyperlink","data":{"link_type":"Web","url":"https://kccna18.sched.com/event/GrXX/adopting-prometheus-the-hard-way-tim-simmons-digitalocean"}}]},{"type":"paragraph","text":"Happy Coding,","spans":[]},{"type":"paragraph","text":"Phil Dougherty,","spans":[]},{"type":"paragraph","text":"Sr. Product Manager","spans":[]}],"blog_post_date":"2018-12-11","tags":[{"tag1":{"tag":"Product Updates","_linkType":"Link.document","_meta":{"uid":"product-updates"}}}],"_meta":{"uid":"digitalocean-releases-k8s-as-a-service"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"TC Currie","author_image":{"dimensions":{"width":1372,"height":1352},"alt":"TC Currie","copyright":null,"url":"https://images.prismic.io/www-static/c97b5e9a80062bc03c460bbd59e8aa8aa45428f6_tc-dangerous-nite1.jpg?auto=compress,format"},"_meta":{"uid":"tc_currie"}},"blog_header_image":{"dimensions":{"width":784,"height":418},"alt":"Illustration of Male developer on computer","copyright":null,"url":"https://images.prismic.io/www-static/b5fe7883969b168ed4dd40ce8260539595a7d2ab_outlinevpn_social_blog--1-.png?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"With DigitalOcean, Jigsaw's Private VPN Gives a Line Out to Journalists","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"Imagine you’re a journalist covering an uprising against a military regime.  You film a riot on your phone, then quickly send it to your server over the virtual private network (VPN) you found in the Android app store that promised high security.  That night, when you finally make it back to your hotel room and boot up your laptop to write the story, you realize the video is nowhere to be found.","spans":[]},{"type":"paragraph","text":"Unbeknownst to you, this government forced your VPN provider to give them access to all the data streaming through their VPN as a condition for operating in their country. Censors grabbed your video and the pictures worth a thousand words never make it to your server. But that fact was never mentioned anywhere in the Android store’s description of the product.","spans":[]},{"type":"paragraph","text":"This type of scenario isn’t hypothetical. “Journalists should be aware that their online activities might be subject to surveillance either by government agencies, their internet service providers or a hacker with malicious intent,” said Laura Tich, technical evangelist for Code for Africa, a resource for African journalists. This is exactly the problem that the new private VPN Outline was created to solve.","spans":[{"start":275,"end":290,"type":"hyperlink","data":{"link_type":"Web","url":"http://codeforafrica.org"}},{"start":381,"end":388,"type":"hyperlink","data":{"link_type":"Web","url":"https://getoutline.org/en/home"}}]},{"type":"paragraph","text":"Alphabet’s cybersecurity division Jigsaw designed the product for ease of use and maximum data security. Outline, which is open source and audited by the Radically Open Security, is targeted to journalists and activists working for change on a large scale. Those who are disproportionately more valuable to society because they are carriers of societal change, said Santiago Andrigo, Jigsaw’s product manager, who manages Outline.","spans":[{"start":34,"end":40,"type":"hyperlink","data":{"link_type":"Web","url":"https://jigsaw.google.com/"}},{"start":366,"end":382,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.linkedin.com/in/santiagoandrigo/"}}]},{"type":"paragraph","text":"“Their work makes them more vulnerable to attack,” he said.  “It can get really scary when they're outed and you're passing over information.”","spans":[]},{"type":"heading3","text":"The Danger is Real","spans":[]},{"type":"paragraph","text":"Laura Tich, the technical evangelist, is only too aware of this danger. It’s why Code For Africa recommends the use of Outline. The jeopardy is not just for journalists, but for whistleblowers, sources, and the data they provide as proof of corruption.","spans":[]},{"type":"paragraph","text":"“As surveillance becomes ubiquitous in today’s world,” she said, “journalists face an increasing challenge in establishing secure communication in the digital space,” she said. This, along with other online attacks “pose serious threats to journalists who would like to protect not only themselves, but also their sources.”","spans":[]},{"type":"paragraph","text":"One example, said Tich, is the arrest of Nigerian journalist Tony Ezimakor for writing a story about alleged ransom money kickbacks. The State Security Service demanded he disclose his sources.","spans":[]},{"type":"paragraph","text":"Another example she cited is the report from the South African campaign Right2Know, whose mission is centered on freedom of expression and access to information.","spans":[{"start":72,"end":82,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.r2k.org.za"}}]},{"type":"paragraph","text":"Right2Know’s recently-released report \"Spooked: Surveillance of Journalists in South Africa\" [PDF] has 10 specific examples of targeted surveillance by security agencies towards journalists and whistleblowers, especially those who have uncovered government scandals and corruption cases, she said. And that’s just from one country.","spans":[{"start":93,"end":98,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.r2k.org.za/wp-content/uploads/R2K-Surveillance-of-Journalists-Report-2018-web.pdf"}}]},{"type":"paragraph","text":"These are far from isolated incidents. The 2018 World Press Freedom Index report is proof that the world has become a more dangerous place for journalists.","spans":[{"start":43,"end":80,"type":"hyperlink","data":{"link_type":"Web","url":"https://rsf.org/en/ranking"}}]},{"type":"paragraph","text":"“You’re only as safe as your weakest link,” said Dan Keyserling, Head of Communications, Public Affairs, and Operations at Jigsaw.  Data security is always critical, he said, but that is especially true for journalists and activists.","spans":[{"start":49,"end":63,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.linkedin.com/in/dan-keyserling-6b42229/"}}]},{"type":"heading3","text":"How VPNs Really Works","spans":[]},{"type":"paragraph","text":"I was really surprised to find out that companies can reach in and grab data out of a VPN.  I’ve been using them since my early days as a consultant back in the ‘90s.  At every job, I’d VPN into the company network to send over timecards and documentation from Racine, WI; Bentonville, AR; or, whatever exotic local I was flying to that week.  Until researching this article, I thought of VPNs like a transit tube where the data is put into the tube, then pulled out on the other end—like the Chunnel.  I assumed the data was secure and invisible during transit, which was, after all, the whole point of a VPN.","spans":[]},{"type":"paragraph","text":"It turns out, they’re more like a river, where the stream of data flowing by can be seen and fished out.","spans":[]},{"type":"paragraph","text":"Unscrupulous VPN providers can peek in on your data, inject their own ads on non-secure pages, analyze your browsing habits, and sell that information to advertisers, said Keyserling. Or even steal your identity. And you can’t know for sure if you can trust them, regardless of what they say in the app store.","spans":[]},{"type":"paragraph","text":"While it’s true that so much data flows through VPNs that it’s not practical to monitor all the data, the fact remains that it is possible. As seen above, journalists and others working to expose corruption are particularly vulnerable.  This is exactly why companies build their own VPNs.","spans":[]},{"type":"paragraph","text":"But what is a non-technical journalist or social justice activist to do?","spans":[]},{"type":"paragraph","text":"[Related: Check out our Community Tutorials on VPNs]","spans":[{"start":0,"end":52,"type":"strong"},{"start":10,"end":51,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/community/tags/vpn?type=tutorials"}}]},{"type":"heading3","text":"Enter Outline","spans":[]},{"type":"paragraph","text":"The private VPN focuses on security and simplicity. This tech is really innovative and took several years to build, said Keyserling. An innovative layer of security comes under the hood.  “It’s a clever product and very technically advanced, and puts security in the hands of the small innovator.”","spans":[]},{"type":"paragraph","text":"They named the product Outline because it “gives them a line out, from a place where the internet is restricted,” said Keyserling.","spans":[]},{"type":"paragraph","text":"Outline is specifically designed to be resistant to censorship.  Because of the protocols used, Outline is harder to detect as a VPN, and therefore is less likely to be blocked by countries who take measure to block the flow of content out of their country.","spans":[]},{"type":"paragraph","text":"With Outline, said Keyserling, each account uses its own DigitalOcean servers, so you get complete control over your data. In addition, Jigsaw brings that power into the hands of anyone with a phone. Now users can create their own personal VPN to their own personal server, said Keyserling: “It is super simple and very affordable.  They don’t need to trust a third-party VPN company.”","spans":[]},{"type":"heading3","text":"We Found Your Server","spans":[]},{"type":"paragraph","text":"Outline is insanely easy to spin up, which is a critical part of the design.  And because ease of use was the most important feature, DigitalOcean was the obvious choice when Jigsaw started looking for partners.","spans":[]},{"type":"paragraph","text":"While you can build an Outline VPN on a different server, the UI was designed to work with DigitalOcean. “DigitalOcean is the default and what we recommend,” said Keyserling, “because the UI we built with DigitalOcean is nicer, slicker than the rest, and a little bit easier for our users.”","spans":[]},{"type":"paragraph","text":"Users can create their own private VPN in three easy, self-explanatory steps following the prompts at GetOutline.org. Sign up, pick a server location, and add users and boom! You have your own secure VPN feeding into your own server in five to seven minutes.  If you can create an email account, you can set up an Outline VPN.","spans":[{"start":102,"end":116,"type":"hyperlink","data":{"link_type":"Web","url":"http://GetOutline.org"}}]},{"type":"paragraph","text":"It’s just as simple to add users.  For example, a journalist has found a whistleblower source and wants to add them to her VPN to transfer the incriminating files.  The journalist adds the whistleblower to her VPN, then sends them an email from Outline that contains an access code as a link, along with simple instructions. When the whistleblower copies the access code into their browser, an “Add Server” button pops up.  They click the button and the application connects them, and then shows the message, “We found your server.” They’re off and running.","spans":[]},{"type":"paragraph","text":"“It knows which server because they just copied it to the clipboard,” said Andrigo.  “It leads me to installing the right client and upon opening that client, it already knows which server I was invited to so it just automatically adds in.”","spans":[]},{"type":"heading3","text":"Behind the Curtain","spans":[]},{"type":"paragraph","text":"It’s not that simple, of course.  That five-minute magic is hiding a lot of complexity.","spans":[]},{"type":"paragraph","text":"Which was the goal, said Andrigo.  “Outline is about taking something that is very complex and making it simple, making meaningful choices for the user, and hiding the complexity.”","spans":[]},{"type":"paragraph","text":"Once the user chooses a server location, Outline spins up a DigitalOcean server on Ubuntu, installs Docker, and imports an image that has the actual server itself.  Then it installs a component of Watchtower, which makes sure that the server is always up to date so the user doesn’t have to worry about installing a steady stream of security updates.","spans":[]},{"type":"paragraph","text":"Outline relies on the Shadowsocks protocol, which is an open-source project to create an encrypted socks5 proxy to redirect internet traffic.","spans":[{"start":22,"end":33,"type":"hyperlink","data":{"link_type":"Web","url":"https://en.wikipedia.org/wiki/Shadowsocks"}}]},{"type":"paragraph","text":"By contrast, a socks5 proxy looks like normal internet traffic. What this means is that your new Outline VPN doesn’t look like a VPN, so your data doesn’t get flagged or monitored by countries that regulate data in and out of their borders.  Which is crazy helpful to journalists and activists who are working in dangerous parts of the world.","spans":[]},{"type":"paragraph","text":"Outline’s ease of use did not come easily. “We did a lot of usability studies,” said Andrigo, “because we are lucky enough to have a very strong design and usability team, and we went through a lot of iterations to figure out what models of user interaction are clear.”","spans":[]},{"type":"paragraph","text":"One surprising result from their usability studies led to actually adding a step in the process.  “Sometimes things happened so fast that some of the users got startled,\" he noted.  They actually slowed the install process to make it easier to use.","spans":[]},{"type":"paragraph","text":"The end result?  A super simple, super safe way to transfer data for people with limited technical ability.","spans":[]},{"type":"paragraph","text":"For Andrigo, that what makes it all worthwhile.  “Those moments,” he said, “where you take something that is very complex and you make it simple and remove all that complexity and you hopefully make wise choices for the user about the things that they don't need to know and that stand in the way of them getting their job done.”","spans":[]},{"type":"paragraph","text":"[Read more TC Currie: How 2,000 Droplets Broke the Enigma Code in 13 Minutes]","spans":[{"start":0,"end":77,"type":"strong"},{"start":22,"end":76,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/how-2000-droplets-broke-the-enigma-code-in-13-minutes/"}}]},{"type":"paragraph","text":"TC Currie is a journalist, storyteller, data geek, poet, body positive activist and occasional lingerie model. After spending 25 years in software development working with data movement and accessibility, she wrote her first novel during National Novel Writing Month and fell in love with writing.","spans":[{"start":0,"end":297,"type":"em"}]}],"blog_post_date":"2018-11-23","tags":[{"tag1":{"tag":"Engineering","_linkType":"Link.document","_meta":{"uid":"engineering"}}}],"_meta":{"uid":"digitalocean-outline-jigsaw-vpn"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"Daniel Zaltsman","author_image":{"dimensions":{"width":188,"height":188},"alt":"Daniel Zaltsman","copyright":null,"url":"https://images.prismic.io/www-static/663d428f56c46eeb165c811add8f1f60402aa451_daniel_zaltsman-c47f4847.png?auto=compress,format"},"_meta":{"uid":"daniel_zaltsman"}},"blog_header_image":{"dimensions":{"width":784,"height":418},"alt":"Hacktoberfest H with a Woman developer sitting on the end of the H working","copyright":null,"url":"https://images.prismic.io/www-static/ef44e76db7aad43808d319f25fe2865d6020de35_hacktoberfest_blog.png?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"A Review of Hacktoberfest Year 5!","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"Five years ago the community team at DigitalOcean wanted to create a program to inspire open source contributions. That first year, in 2014, the first Hacktoberfest participants were asked for 50 commits, and those who completed the challenge received a reward of swag. 676 people signed up and 505 forged ahead to the finish line, earning stickers and a custom limited-edition T-shirt.","spans":[{"start":141,"end":164,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.digitalocean.com/hacktoberfest/"}},{"start":270,"end":273,"type":"strong"},{"start":295,"end":298,"type":"strong"}]},{"type":"paragraph","text":"This year that number is an astounding 46,088 completions out of 106,582 sign-ups. We’ve seen it become an entry point to developers contributing to open source projects: much more than a program, it’s clear that Hacktoberfest has become a global community movement with a shared set of values and passion for giving back. It’s been a pleasure to be behind the scenes watching it grow every year, and in this post we’ll share what we saw from all of you in the 5th anniversary.","spans":[{"start":39,"end":45,"type":"strong"},{"start":65,"end":72,"type":"strong"}]},{"type":"paragraph","text":"Before getting into the data, we owe a thank you to our partners; GitHub (4th time partner) and Twilio (1st time partner), thank you for the support and guidance in planning, promotion, and production.","spans":[{"start":66,"end":72,"type":"strong"},{"start":96,"end":102,"type":"strong"}]},{"type":"paragraph","text":"Also, thank you to the maintainers of open source repositories on GitHub, for dedicating your blood (maybe?), sweat (likely), and tears (definitely!) to making this celebration possible for all the active participants around the world. We proclaim you the ‘Heroes of Hacktoberfest’ and have something to offer if you read to the end of this post.","spans":[{"start":236,"end":346,"type":"em"},{"start":329,"end":346,"type":"hyperlink","data":{"link_type":"Web","url":"#heroes"}}]},{"type":"heading3","text":"What happens when the world contributes","spans":[]},{"type":"paragraph","text":"Without further ado, here are some of the high-level stats from this year’s Hacktoberfest, all measuring the impact on open source you collectively created in the month of October.","spans":[]},{"type":"list-item","text":"Pull Requests from all participants: 412,324","spans":[{"start":37,"end":44,"type":"strong"}]},{"type":"list-item","text":"Participating repositories: 106,582","spans":[{"start":28,"end":35,"type":"strong"}]},{"type":"list-item","text":"Day with the most PRs: 20,300 on October 2nd","spans":[{"start":23,"end":29,"type":"strong"}]},{"type":"list-item","text":"Repo with most PRs: FreeCodeCamp with 12,090","spans":[{"start":38,"end":44,"type":"strong"}]},{"type":"list-item","text":"Participating Countries, based on addresses: 143","spans":[{"start":45,"end":48,"type":"strong"}]},{"type":"paragraph","text":"Behind those large-scale numbers are real stories of impact from various developer communities. Here are just a few that have already shared the impact and lessons learned: Gatsby.js, Kowainik, source{d}, weaveworks, and opsdroid.","spans":[{"start":173,"end":182,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.gatsbyjs.org/blog/2018-11-01-hacktoberfest-wrapup/?no-cache=1"}},{"start":184,"end":192,"type":"hyperlink","data":{"link_type":"Web","url":"https://kowainik.github.io/posts/2018-11-01-hacktoberfest-wrap-up"}},{"start":194,"end":203,"type":"hyperlink","data":{"link_type":"Web","url":"https://medium.com/sourcedtech/its-a-wrap-source-d-s-participation-in-hacktoberfest-9223814a6a49"}},{"start":205,"end":215,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.weave.works/blog/hacktoberfest-2018-its-a-wrap"}},{"start":221,"end":229,"type":"hyperlink","data":{"link_type":"Web","url":"https://medium.com/opsdroid/hacktoberfest-website-refresh-core-connectors-and-more-in-v0-13-9f3d3326427d"}}]},{"type":"paragraph","text":"Part of what makes Hacktoberfest possible are the vibrant developer communities that keep participating year after year. Some examples are Elastic, Changelog, Jenkins, Godot Engine, Home Assistant, OpenEBS, SendGrid, Hasura, Mattermost, dbatools, and many more.","spans":[{"start":139,"end":146,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.elastic.co/blog/hacktoberfest-2018-for-beats-and-logstash"}},{"start":148,"end":157,"type":"hyperlink","data":{"link_type":"Web","url":"https://changelog.com/news/get-your-hacktoberfest-shirt-without-writing-a-lick-of-code-2bzD"}},{"start":159,"end":166,"type":"hyperlink","data":{"link_type":"Web","url":"https://jenkins.io/blog/2018/10/01/hacktoberfest/"}},{"start":168,"end":180,"type":"hyperlink","data":{"link_type":"Web","url":"https://godotengine.org/article/become-godot-contributor-hacktoberfest-2018"}},{"start":182,"end":196,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.home-assistant.io/blog/2018/09/30/hacktoberfest/"}},{"start":198,"end":205,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.openebs.io/celebrate-hacktoberfest-2018-with-openebs-206daa1d653c"}},{"start":207,"end":215,"type":"hyperlink","data":{"link_type":"Web","url":"https://sendgrid.com/blog/hacktoberfest-2018-has-arrived/"}},{"start":217,"end":223,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.hasura.io/announcing-hacktoberfest-2018-with-hasura-621045dc9560"}},{"start":225,"end":235,"type":"hyperlink","data":{"link_type":"Web","url":"https://mattermost.com/blog/hacktoberfest-2018-is-here-its-a-chance-to-give-back-to-communities-you-love/"}},{"start":237,"end":245,"type":"hyperlink","data":{"link_type":"Web","url":"https://dbatools.io/hacktoberfest/"}}]},{"type":"heading3","text":"We’re all just getting started","spans":[]},{"type":"paragraph","text":"For many of you, Hacktoberfest was the first time getting involved in open source. This is a story we love to hear and we sometimes know where it leads. Here are participants’ stories who were beginners last year and have gone on to make strides in their work in 2018:","spans":[]},{"type":"paragraph","text":"Last year, people helped me create my first PR. I decided to pay back by helping people get theirs. I think that was my most valuable contribution this year. - Nikhil (India)","spans":[{"start":0,"end":174,"type":"em"}]},{"type":"paragraph","text":"I first began my Hacktoberfest quest last year. I was always inspired by people who contributed to open source software projects and aspired to one day be part of such a community. Hacktoberfest really got me started and I now am motivated to do this year wide whenever I have the time. - Constantinos (Greece)","spans":[{"start":0,"end":310,"type":"em"}]},{"type":"paragraph","text":"It's the second year participating, I keep encouraging people to participate as my first PR was in such an empowering and welcoming environment last year :) - Saul (Mexico)","spans":[{"start":0,"end":172,"type":"em"}]},{"type":"paragraph","text":"I made my first contribution to the open source last year under the influence of Hacktoberfest, that got me excited and I keep making uncountable contributions since then!! -Aminu (Nigeria)","spans":[{"start":0,"end":189,"type":"em"}]},{"type":"paragraph","text":"Last year was my first Hacktoberfest and I was a dev student trying to make my way into the field. For this year's Hacktoberfest, I'm an actual professional developer at a company!!!! -Tyler (USA)","spans":[{"start":0,"end":196,"type":"em"}]},{"type":"heading3","text":"Think globally, act locally","spans":[]},{"type":"paragraph","text":"From the beginning, Hacktoberfest has been inspired by developers who come together in real life to learn, build, and connect. Still, it is unexpected and absolutely remarkable to see the statistics from this year’s global events. For year 5 there were 267 events (compared with 119 events in 2017), organized in 50 countries! Here are the top 10 countries (and cities) by total events organized:","spans":[{"start":253,"end":256,"type":"strong"},{"start":253,"end":263,"type":"hyperlink","data":{"link_type":"Web","url":"https://do.co/hacktoberfest18events"}},{"start":279,"end":282,"type":"strong"},{"start":313,"end":315,"type":"strong"}]},{"type":"o-list-item","text":"India - 49 Events (Most in Bengaluru)","spans":[]},{"type":"o-list-item","text":"USA - 46 Events (Most in Atlanta)","spans":[]},{"type":"o-list-item","text":"Brazil - 20 Events (Most in Rio de Janeiro)","spans":[]},{"type":"o-list-item","text":"France - 15 Events (Most in Paris)","spans":[]},{"type":"o-list-item","text":"United Kingdom - 14 Events (Most in London)","spans":[]},{"type":"o-list-item","text":"Germany - 12 Events (Most in Berlin)","spans":[]},{"type":"o-list-item","text":"Canada - 11 Events (Most in Edmonton)","spans":[]},{"type":"o-list-item","text":"Mexico - 9 Events (Most in Guadalajara)","spans":[]},{"type":"o-list-item","text":"Poland - 8 Events (Most in Białystok)","spans":[]},{"type":"o-list-item","text":"Italy / Nigeria / Spain - 6 Events","spans":[]},{"type":"paragraph","text":"This would not have been possible without the impassioned community organizers around the world, who live and breathe events. You too have earned the title of ‘Heroes of Hacktoberfest!’ And a special thank you goes to Samantha Tse (DigitalOcean) and Joe Nash (GitHub) who created the invaluable Hacktoberfest Event Kit and supported organizers all month long.","spans":[{"start":126,"end":185,"type":"em"},{"start":218,"end":230,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/tse_samantha"}},{"start":250,"end":258,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/jna_sh"}},{"start":295,"end":318,"type":"hyperlink","data":{"link_type":"Web","url":"https://hacktoberfest.digitalocean.com/eventkit"}}]},{"type":"paragraph","text":"Here is some of the action from this year’s in-person gatherings:","spans":[]},{"type":"preformatted","text":"An awesome event for hacktoberfest! @ SIES Graduate School of Technology@github@digitalocean@hacktoberfest#Hacktoberfest2018#latepostpic.twitter.com/s6B9f7NyY6\n— Chinmay Chandak (@CCAtAlvis) October 31, 2018","spans":[{"start":72,"end":79,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/github?ref_src=twsrc%5Etfw"}},{"start":79,"end":92,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/digitalocean?ref_src=twsrc%5Etfw"}},{"start":92,"end":106,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hacktoberfest?ref_src=twsrc%5Etfw"}},{"start":106,"end":124,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/Hacktoberfest2018?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":124,"end":133,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/latepost?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":133,"end":159,"type":"hyperlink","data":{"link_type":"Web","url":"https://t.co/s6B9f7NyY6"}},{"start":191,"end":207,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/CCAtAlvis/status/1057721180839464960?ref_src=twsrc%5Etfw"}}]},{"type":"preformatted","text":"Hosting the #Hacktoberfest in #Sarajevo second year running has been an amazing experience with some of my most favorite people in the world. It was also my first experience as a #Fireside Chat panel moderator! Lost of love and effort went into making the event awesome! pic.twitter.com/oDkPIh3wT4\n— Adnan Rahić (@adnanrahic) October 29, 2018","spans":[{"start":12,"end":26,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/Hacktoberfest?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":30,"end":39,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/Sarajevo?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":179,"end":188,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/Fireside?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":271,"end":297,"type":"hyperlink","data":{"link_type":"Web","url":"https://t.co/oDkPIh3wT4"}},{"start":326,"end":342,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/adnanrahic/status/1056869064184868864?ref_src=twsrc%5Etfw"}}]},{"type":"preformatted","text":"We're at @hacktoberfest in Frankfurt. Awesome crowd, great food and open source. We're happy we can be a part of it! #hacktoberfest#Hacktoberfest2018#hacktoberfestffmpic.twitter.com/tYBiB79wwK\n— Rocketloop (@RocketloopHQ) October 12, 2018","spans":[{"start":9,"end":23,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hacktoberfest?ref_src=twsrc%5Etfw"}},{"start":117,"end":131,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/hacktoberfest?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":131,"end":149,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/Hacktoberfest2018?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":149,"end":166,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/hacktoberfestffm?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":166,"end":192,"type":"hyperlink","data":{"link_type":"Web","url":"https://t.co/tYBiB79wwK"}},{"start":222,"end":238,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/RocketloopHQ/status/1050800207565340674?ref_src=twsrc%5Etfw"}}]},{"type":"preformatted","text":"Badass @FlatironSchool team (and others!) At the @gdinyc#Hacktoberfest event today! I had so much fun actually coding with people in person. #WomenWhoCode#WomenInTechpic.twitter.com/m4YPRCKSQ3\n— Amanda🔮🌻👩🏻‍💻 (@amandacodes89) October 21, 2018","spans":[{"start":7,"end":22,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/FlatironSchool?ref_src=twsrc%5Etfw"}},{"start":49,"end":56,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/gdinyc?ref_src=twsrc%5Etfw"}},{"start":56,"end":70,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/Hacktoberfest?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":141,"end":154,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/WomenWhoCode?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":154,"end":166,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/WomenInTech?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":166,"end":192,"type":"hyperlink","data":{"link_type":"Web","url":"https://t.co/m4YPRCKSQ3"}},{"start":225,"end":241,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/amandacodes89/status/1053835986399059968?ref_src=twsrc%5Etfw"}}]},{"type":"heading3","text":"Short term action, long term impact","spans":[]},{"type":"paragraph","text":"The values of Hacktoberfest remind us why we celebrate open source software. It is about creating an inclusive community that builds together to makes the world a better place. What happened during Hacktoberfest will have a lasting impact on people long after October 2018. This is why quality is preferred to quantity and why we’ll continue to improve the program to support this core value.","spans":[{"start":4,"end":27,"type":"hyperlink","data":{"link_type":"Web","url":"https://hacktoberfest.digitalocean.com/details/#values"}}]},{"type":"paragraph","text":"One thing that you can expect to see every year is the custom limited-edition t-shirts. Fun fact: the first batch of t-shirts we produced this year weighed 21,000 pounds (9,500 kg) and stickers weighed 650 pounds (295 kg). Better than stats, here's you, the participants who completed the challenge:","spans":[{"start":156,"end":162,"type":"strong"},{"start":171,"end":176,"type":"strong"},{"start":202,"end":205,"type":"strong"},{"start":214,"end":217,"type":"strong"}]},{"type":"preformatted","text":"My #hacktoberfest swag just got in yesterday! 🎉🎊 Thank you digitalocean for hosting the 5th Hacktoberfest Fest, and supporting thousands of open source projects 🔥👊🏻👨🏻‍💻 https://t.co/OqVdcFUyewpic.twitter.com/YH8l1gszR2\n— Aral Taşer (@araltasher) November 7, 2018","spans":[{"start":3,"end":17,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/hacktoberfest?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":169,"end":192,"type":"hyperlink","data":{"link_type":"Web","url":"https://t.co/OqVdcFUyew"}},{"start":192,"end":218,"type":"hyperlink","data":{"link_type":"Web","url":"https://t.co/YH8l1gszR2"}},{"start":246,"end":262,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/araltasher/status/1060213995536347138?ref_src=twsrc%5Etfw"}}]},{"type":"preformatted","text":"Im never big on selfies, but I am really proud of this shirt #Hacktoberfest2018pic.twitter.com/k7rR68mynG\n— Cam Barts (@cam_barts) November 5, 2018","spans":[{"start":61,"end":79,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/Hacktoberfest2018?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":79,"end":105,"type":"hyperlink","data":{"link_type":"Web","url":"https://t.co/k7rR68mynG"}},{"start":131,"end":147,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/cam_barts/status/1059448612445454338?ref_src=twsrc%5Etfw"}}]},{"type":"preformatted","text":"\"Woman laughing alone with #hacktoberfest shirt\" ... GOT IT! EXCITED! Thanks, @digitalocean 😍 #happysaturday#opensource#dev#keepcoding#gosteelerspic.twitter.com/KCA1sRESLe\n— Kristen Seversky (@KR1573N) November 3, 2018","spans":[{"start":27,"end":41,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/hacktoberfest?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":78,"end":91,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/digitalocean?ref_src=twsrc%5Etfw"}},{"start":94,"end":108,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/happysaturday?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":108,"end":119,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/opensource?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":119,"end":123,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/dev?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":123,"end":134,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/keepcoding?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":134,"end":145,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/gosteelers?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":145,"end":171,"type":"hyperlink","data":{"link_type":"Web","url":"https://t.co/KCA1sRESLe"}},{"start":202,"end":218,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/KR1573N/status/1058759919887884289?ref_src=twsrc%5Etfw"}}]},{"type":"preformatted","text":"V excited to have participated in #hacktoberfest! (but also to get a free t-shirt which is ofc the main reason anyone goes into tech) pic.twitter.com/98RaX2HxfB\n— Alexandra Fren (@alexandrafren) November 3, 2018","spans":[{"start":34,"end":48,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/hacktoberfest?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":134,"end":160,"type":"hyperlink","data":{"link_type":"Web","url":"https://t.co/98RaX2HxfB"}},{"start":195,"end":211,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/alexandrafren/status/1058829276387180544?ref_src=twsrc%5Etfw"}}]},{"type":"paragraph","text":"As with previous years, spam is something not to be taken lightly when we are planning the program. This year we introduced a section for beginners, published quality standards, and included the program values in most of our communications to participants. Still we saw a hefty increase in Pull Requests labelled ‘Invalid.' From a manageable 1,861 in 2017 (.8% of total) to an unfortunate 11,083 (2.7%) in 2018.","spans":[{"start":342,"end":347,"type":"strong"},{"start":389,"end":395,"type":"strong"}]},{"type":"paragraph","text":"This means we’re going back to the drawing board and will be taking new measures to fight spam in 2019. Should we introduce reward tiers? Restrict PRs to personal projects? Or something else all together? Have ideas for minimizing invalid PRs? Leave a suggestion in the comments.","spans":[]},{"type":"heading3","text":"Closing remarks for 2018","spans":[]},{"type":"paragraph","text":"The great news is that Hacktoberfest is not really a month-long celebration of open source - it’s a culture and community that is always looking to give back. Through this ongoing work, we can accomplish almost anything we set our minds to. We’re looking forward to seeing what you have and will build all year long.","spans":[]},{"type":"paragraph","text":"SUPPORT: for all support-related inquiries about emails, usernames, addresses, and t-shirts, please contact our team as soon as possible: Hacktoberfest [at] DigitalOcean [dot] com.","spans":[]},{"type":"paragraph","text":"REMINDER: Keep a look-out for our first ever post-Hacktoberfest survey in which we’ll ask for your feedback on everything from the events, support, and t-shirts, set to go out in early December.","spans":[]},{"type":"paragraph","text":"Note to maintainers and meetup organizers: If you organized an event for +25 people or are a maintainer of a repo on GitHub that received 100 or more Pull Requests and has upwards of 500 stars, please reach out to us at the support email address above for a special thank you from us to you.","spans":[{"start":0,"end":41,"type":"em"}]}],"blog_post_date":"2018-11-09","tags":[{"tag1":{"tag":"Community","_linkType":"Link.document","_meta":{"uid":"community"}}}],"_meta":{"uid":"a-review-of-hacktoberfest-year-5"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"Brett Jones","author_image":null,"_meta":{"uid":"brett_jones"}},"blog_header_image":{"dimensions":{"width":784,"height":418},"alt":null,"copyright":null,"url":"https://images.prismic.io/www-static/bb6388a8-b308-4840-9ebb-21636b4f19e8_ComparingStrings_blog.png?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"How to Efficiently Compare Strings in Go","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"Comparing strings might not be something you think about when optimizing software. Typically, optimization includes tasks like splitting loops across goroutines, finding a faster hashing algorithm, or something that sounds more scientific. There is a sense of accomplishment we get when making changes like this. However, string comparison can often be the top bottleneck in a pipeline. For example, the snippet below is often used, but it is the worst solution (benchmarks below) and it has caused real problems.","spans":[]},{"type":"paragraph","text":"```[php]{`strings.ToLower(name) == strings.ToLower(othername)`}```","spans":[]},{"type":"paragraph","text":"This appears to be pretty straightforward. Convert each string to lowercase and then compare. To understand why this is a bad solution you have to know what a string represents and how `ToLower` works. ","spans":[]},{"type":"paragraph","text":"But first, let's talk about the primary use-cases for string comparisons. When comparing using the normal `==` operator, we get the quickest and most optimized solution. However, APIs and similar software usually take case into consideration. This is when we drop in `ToLower` and call it feature-complete.","spans":[]},{"type":"paragraph","text":"In Go, a string is an immutable sequence of runes. Rune is a term Go uses to represent a code point. You can read more about strings, bytes, runes and characters at the Go blog. `ToLower` is a standard library function that loops over each rune in a string, converts it to lowercase, and returns the newly formed string. So the above code traverses each string entirely before the comparison. It is tight-bound to the length of the strings. Here is some pseudo code that roughly represents the complexity of the above snippet.","spans":[{"start":89,"end":99,"type":"hyperlink","data":{"link_type":"Web","url":"https://en.wikipedia.org/wiki/Code_point"}},{"start":169,"end":176,"type":"hyperlink","data":{"link_type":"Web","url":"https://blog.golang.org/strings"}}]},{"type":"paragraph","text":"Note: Because strings are immutable, ```[php]{`strings.ToLower`}``` allocates new memory space for two new strings. This contributes to the time complexity, but this is not the focus now. For brevity, the pseudo code below assumes that strings are mutable.","spans":[{"start":0,"end":37,"type":"em"},{"start":47,"end":62,"type":"em"},{"start":67,"end":256,"type":"em"}]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    // Pseudo code","spans":[]},{"type":"paragraph","text":"    func CompareInsensitive(a, b string) bool {  ","spans":[]},{"type":"paragraph","text":"        // loop over string a and convert every rune to lowercase","spans":[]},{"type":"paragraph","text":"        for i := 0; i < len(a); i++ {  a[i] = unicode.ToLower(a[i])  }","spans":[]},{"type":"paragraph","text":"        // loop over string b and convert every rune to lowercase","spans":[]},{"type":"paragraph","text":"        for i := 0; i < len(b); i++ {  b[i] = unicode.ToLower(b[i])  }","spans":[]},{"type":"paragraph","text":"        // loop over both a and b and return false if there is a mismatch","spans":[]},{"type":"paragraph","text":"        for i := 0; i < len(a); i++ {","spans":[]},{"type":"paragraph","text":"            if a[i] != b[i] { ","spans":[]},{"type":"paragraph","text":"                return false","spans":[]},{"type":"paragraph","text":"            }","spans":[]},{"type":"paragraph","text":"        }","spans":[]},{"type":"paragraph","text":"        return true","spans":[]},{"type":"paragraph","text":"    }","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"paragraph","text":"The time complexity is O(n) where n is len(a) + len(b) + len(a). Here's an example: ","spans":[]},{"type":"paragraph","text":"```[php]{`CompareInsensitive(\"fizzbuzz\", \"buzzfizz\")`}```","spans":[]},{"type":"paragraph","text":"That means we will loop up to 24 times to discover that two *completely distinct strings* do not match. This is highly inefficient. We could tell these strings were distinct by comparing ```[php]{`unicode.ToLower(a[0])`}``` and ```[php]{`unicode.ToLower(b[0])`}``` (pseudo code). So let’s take that into consideration.","spans":[]},{"type":"paragraph","text":"To optimize, We can *remove* the first two loops in `CompareInsensitive` and compare each character in each position. If runes don’t match, we would then convert the runes to lowercase and then compare again. If they still don’t match then we break the loop and consider the two strings a mismatch. If they match we can continue to the next rune until the end is reached or until a mismatch is found. Let’s rewrite this code.","spans":[]},{"type":"preformatted","text":"```[php]{`","spans":[]},{"type":"paragraph","text":"    // Pseudo code","spans":[]},{"type":"paragraph","text":"    func CompareInsensitive(a, b string) bool {  ","spans":[]},{"type":"paragraph","text":"        // a quick optimization. If the two strings have a different","spans":[]},{"type":"paragraph","text":"        // length then they certainly are not the same","spans":[]},{"type":"paragraph","text":"        if len(a) != len(b) {","spans":[]},{"type":"paragraph","text":"            return false","spans":[]},{"type":"paragraph","text":"        }","spans":[]},{"type":"paragraph","text":"        for i := 0; i < len(a); i++ {","spans":[]},{"type":"paragraph","text":"            // if the characters already match then we don't need to ","spans":[]},{"type":"paragraph","text":"            // alter their case. We can continue to the next rune","spans":[]},{"type":"paragraph","text":"            if a[i] == b[i] { ","spans":[]},{"type":"paragraph","text":"                continue","spans":[]},{"type":"paragraph","text":"            }","spans":[]},{"type":"paragraph","text":"            if unicode.ToLower(a[i]) != unicode.ToLower(b[i]) {","spans":[]},{"type":"paragraph","text":"                // the lowercase characters do not match so these","spans":[]},{"type":"paragraph","text":"                // are considered a mismatch, break and return false","spans":[]},{"type":"paragraph","text":"                return false","spans":[]},{"type":"paragraph","text":"            }","spans":[]},{"type":"paragraph","text":"        }","spans":[]},{"type":"paragraph","text":"        // The string length has been traversed without a mismatch","spans":[]},{"type":"paragraph","text":"        // therefore the two match","spans":[]},{"type":"paragraph","text":"        return true","spans":[]},{"type":"paragraph","text":"    }","spans":[]},{"type":"preformatted","text":"`}```","spans":[]},{"type":"paragraph","text":"The new function is much more efficient. The upper bounds is the length of one string rather than the sum of the length of both strings. What does this look like with our comparison above? Well, the loop will only ever run eight times at most. However, since the first two runes are not the same this loop only runs once. We have optimized our comparison over twenty fold!","spans":[]},{"type":"paragraph","text":"Fortunately, there is a function in the strings package for this. It’s called ```[php]{`strings.EqualFold`}```.","spans":[]},{"type":"heading3","text":"Benchmarks","spans":[]},{"type":"paragraph","text":"When both strings are equal","spans":[{"start":0,"end":27,"type":"strong"}]},{"type":"paragraph","text":"Operations executedNanoseconds (ns) per operationBenchmarkEqualFoldBothEqual-820000000124 ns/opBenchmarkToLowerBothEqual-810000000339 ns/op","spans":[]},{"type":"paragraph","text":"When both strings are equal until the last rune","spans":[{"start":0,"end":47,"type":"strong"}]},{"type":"paragraph","text":"Operations executedNs per operationBenchmarkEqualFoldLastRuneNotEqual-820000000129 ns/opBenchmarkToLowerLastRuneNotEqual-810000000346 ns/op","spans":[]},{"type":"paragraph","text":"When both strings are distinct","spans":[{"start":0,"end":30,"type":"strong"}]},{"type":"paragraph","text":"Operations executedNs per operationBenchmarkEqualFoldFirstRuneNotEqual-830000000011.2 ns/opBenchmarkToLowerFirstRuneNotEqual-810000000333 ns/op","spans":[]},{"type":"paragraph","text":"When both strings have a different case at rune 0","spans":[{"start":0,"end":49,"type":"strong"}]},{"type":"paragraph","text":"Operations executedNs per operationBenchmarkEqualFoldFirstRuneDifferentCase-820000000125 ns/opBenchmarkToLowerFirstRuneDifferentCase-810000000433 ns/op","spans":[]},{"type":"paragraph","text":"When both strings have a different case in the middle","spans":[{"start":0,"end":53,"type":"strong"}]},{"type":"paragraph","text":"Operations executedNs per operationBenchmarkEqualFoldMiddleRuneDifferentCase-820000000123 ns/opBenchmarkToLowerMiddleRuneDifferentCase-810000000428 ns/op","spans":[]},{"type":"paragraph","text":"There is a staggering difference (by 30 times!) when the first rune of each string does not match. This is because instead of looping over both strings and then comparing, the loop only runs one time and immediately returns false. In every case, `EqualFold` outperforms our initial comparison by orders of magnitude.","spans":[]},{"type":"heading3","text":"Does it Matter?","spans":[]},{"type":"paragraph","text":"You might be thinking that 400 nanoseconds does not matter. In most cases you might be right. However, some micro-optimizations are as simple as any other solution. In this case it is easier than the original solution. ","spans":[]},{"type":"paragraph","text":"Quality engineers have simple optimizations in their normal workflow. They don't wait to optimize software once it becomes an issue, they write optimized software from the beginning. Even for the best engineers, it is unlikely and unrealistic to write the most efficient software from the ground up. It is virtually impossible to think of every edge-case and optimize for it. After all, we rarely know the wild behaviors of our users until we set them loose on our software. ","spans":[]},{"type":"paragraph","text":"However, embedding these simple solutions into your normal workflow will improve the lifespan of applications and prevent unnecessary bottlenecks in the future. Even if that bottleneck never matters, you didn't waste any effort.","spans":[]},{"type":"paragraph","text":"Brett Jones is a Senior Software Engineer and Tech Lead for the Insights team at DigitalOcean. He is happily married with two amazing kids. He loves philosophy, history, fantasy books, and the Dallas Stars. You can find his work at github.com/blockloop.","spans":[{"start":0,"end":253,"type":"em"},{"start":232,"end":252,"type":"hyperlink","data":{"link_type":"Web","url":"https://github.com/blockloop"}}]}],"blog_post_date":"2018-11-07","tags":[{"tag1":{"tag":"Engineering","_linkType":"Link.document","_meta":{"uid":"engineering"}}}],"_meta":{"uid":"how-to-efficiently-compare-strings-in-go"}}},{"node":{"author":{"_linkType":"Link.document","author_name":"Hollie Haggans","author_image":{"dimensions":{"width":400,"height":400},"alt":"Hollie Haggans","copyright":null,"url":"https://images.prismic.io/www-static/7793109e3fed5f875dc50b8866c8e631bd51d5b5_0bfbced-1.jpg?auto=compress,format"},"_meta":{"uid":"hollie_haggans"}},"blog_header_image":{"dimensions":{"width":784,"height":418},"alt":"photo collage of lots of different people ","copyright":null,"url":"https://images.prismic.io/www-static/814c877d54b92e4ed9cae544ee38b55b00123e26_hatch-post.jpg?auto=compress,format"},"blog_headline":[{"type":"heading1","text":"Hatch Turns 2: A Story of 2,000 Startups and 20 Million Droplets","spans":[]}],"blog_post_content":[{"type":"paragraph","text":"Hatch, our global startup program, hit a major milestone this fall turning two!","spans":[{"start":0,"end":33,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.digitalocean.com/hatch/"}}]},{"type":"paragraph","text":"We've made significant progress since launch. We’ve partnered with over 400 incubators, venture capital firms, and accelerators globally to provide a range of perks and support to over 2,000 startups. And, our Hatchers have spun up over 20 million Droplets from 92 countries. We get the excitement around reaching another year, as we've seen it reflected in the eyes of founders traversing the ups and downs of pursuing a dream.","spans":[]},{"type":"paragraph","text":"Community is at the heart of Hatch, and listening to our members is central to continually improving the program. (A highlight was traveling last year to Lisbon for the first time to attend Web Summit, where Hatchers and customers shared their needs and more ways we could support them.) We've heard how Hatch helps members innovate, stress-test new business ideas for clients, and feel supported by a community on a similar journey. As Hatcher James Gallagher, founder of OpenCommit, puts it: \"I have only just joined the Hatch program and I feel that it will help me connect with fellow founders, get feedback for my startup, and help others build their startups.”","spans":[{"start":473,"end":483,"type":"hyperlink","data":{"link_type":"Web","url":"http://opencommit.com"}}]},{"type":"preformatted","text":"It’s party time for Hatch Startups at #WebSummit - customers meeting customers and beautiful views #itshatcheningpic.twitter.com/iUauc9wigq\n— DigitalOcean (@digitalocean) November 8, 2017","spans":[{"start":38,"end":48,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/WebSummit?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":99,"end":113,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/hashtag/itshatchening?src=hash&amp;ref_src=twsrc%5Etfw"}},{"start":113,"end":139,"type":"hyperlink","data":{"link_type":"Web","url":"https://t.co/iUauc9wigq"}},{"start":171,"end":187,"type":"hyperlink","data":{"link_type":"Web","url":"https://twitter.com/digitalocean/status/928340073040445446?ref_src=twsrc%5Etfw"}}]},{"type":"paragraph","text":"We're creating a platform for founders to share their experiences and discuss their companies. For example, at our first North American TIDE event, held in New York City in the spring, a Hatch panel featuring Don Pottinger of Lytham Labs, John Jung of June.ai, and Justin Karneges of Fanout, moderated by Alex Iskold of Techstars, shared how they approached successfully scaling.","spans":[{"start":226,"end":237,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.lythamlabs.com"}},{"start":252,"end":259,"type":"hyperlink","data":{"link_type":"Web","url":"https://june.ai/"}},{"start":284,"end":290,"type":"hyperlink","data":{"link_type":"Web","url":"https://fanout.io"}}]},{"type":"paragraph","text":"","spans":[{"start":0,"end":0,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.youtube.com/watch?v=KQS34toxfB8"}}]},{"type":"image","url":"https://images.prismic.io/www-static/3da9261fa6d1203f0c97d3a737d71fd89eb92fba_building.png?auto=compress,format","alt":null,"copyright":null,"dimensions":{"width":1683,"height":842}},{"type":"paragraph","text":"We'll also continue to support Hatchers through initiatives like the Hatch Founders’ Circles, an invite-only event marked by talks for a curated audience of founders, investors, and startup enablers; as well as Expert Office Hours, such as the one we recently held with our friend and partner, Nic Jackson of Hashicorp.","spans":[{"start":294,"end":318,"type":"hyperlink","data":{"link_type":"Web","url":"https://do.co/hatchslackhashicorp1"}}]},{"type":"paragraph","text":"Our online Slack Community, where founders from all over the world can connect at whatever hour they're up trying to solve problems and help each other reach their goals. “Connecting with various developers across the globe with different skill sets was helpful in getting right answers,\" says Layak Singh, founder of Artivatic.ai. \"Artivatic is working towards deep tech and hence views/knowledge of such diverse group will be really helpful in scaling further.”","spans":[{"start":318,"end":330,"type":"hyperlink","data":{"link_type":"Web","url":"https://artivatic.ai/"}}]},{"type":"paragraph","text":"Hitting our second anniversary wouldn’t be as special without our amazing Hatchers. So we asked them what Hatch has meant. Here’s what some say about their experience:","spans":[]},{"type":"paragraph","text":"","spans":[{"start":0,"end":0,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.youtube.com/watch?v=S4Iaat7j65s&amp;feature=youtu.be"}}]},{"type":"image","url":"https://images.prismic.io/www-static/77b8903fc117c5121924eb9c240194c984714165_hatch-dofo.png?auto=compress,format","alt":null,"copyright":null,"dimensions":{"width":1586,"height":906}},{"type":"paragraph","text":"We are honored to have the opportunity to support a global community of startups that continue to blow us away. Here’s to another year and wave of awesome companies looking to build impactful software. Thanks for all the love and if you are interested in learning more, please visit our program page where you can apply to the program or apply to partner.","spans":[{"start":277,"end":299,"type":"hyperlink","data":{"link_type":"Web","url":"http://do.co/hatch"}}]},{"type":"paragraph","text":"A big thanks to the Hatchers who shared with us:","spans":[{"start":0,"end":48,"type":"em"}]},{"type":"list-item","text":"GogoGoGuest -  Cloud marketing solutions with WiFi service to power food service, hospitality, and pop up retail for smart insights on customers.","spans":[{"start":0,"end":11,"type":"hyperlink","data":{"link_type":"Web","url":"https://gogoguest.com/"}}]},{"type":"list-item","text":"Klayvio - Powerful, easy-to-use email and social marketing platform for eCommerce businesses.","spans":[{"start":0,"end":7,"type":"hyperlink","data":{"link_type":"Web","url":"https://www.klaviyo.com/"}}]},{"type":"list-item","text":"Octochannel - Marketing automation for SMBs and startups.","spans":[{"start":0,"end":11,"type":"hyperlink","data":{"link_type":"Web","url":"https://octochannel.com/"}}]},{"type":"list-item","text":"Dofo - Search platform for domain names.","spans":[{"start":0,"end":4,"type":"hyperlink","data":{"link_type":"Web","url":"https://dofo.com/"}}]},{"type":"list-item","text":"Wingly - Flight sharing platform, finding passengers and pilots for your trip.","spans":[{"start":0,"end":6,"type":"hyperlink","data":{"link_type":"Web","url":"https://en.wingly.io/index.php"}}]},{"type":"list-item","text":"Switch Payments - Switch provides the technical infrastructure for transaction orchestration across the entire payments value chain.","spans":[{"start":0,"end":15,"type":"hyperlink","data":{"link_type":"Web","url":"https://switchpayments.com/#/"}}]}],"blog_post_date":"2018-11-05","tags":[{"tag1":{"tag":"News","_linkType":"Link.document","_meta":{"uid":"news"}}}],"_meta":{"uid":"hatch-turns-2"}}}]}}}