Programming languages allow us to communicate with computers, and they operate like sets of instructions. There are numerous types of languages, including procedural, functional, object-oriented, and more. Whether you’re looking to learn a new language or trying to find some tips or tricks, the resources in the Languages Zone will give you all the information you need and more.
With technological advancements, imagining has played a big role in online communication. Image galleries are the most used ways to showcase images and provide a better user experience. In this tutorial, we will take a walk-through on how to build a modern image gallery using HTML, CSS, and JavaScript. This tutorial will guide you on creating a grid layout, adding hovers to images, and filtering images by categories. By using these skills, you can create a visually appealing and functional image gallery. Whether you are a beginner or an experienced web developer, this tutorial will provide you with the knowledge and skills to create a modern image gallery using the latest web technologies. 1. Set up the HTML Structure Create a basic HTML structure for the image gallery with a container div and a grid div. Inside the grid div, create a div for each image with an img tag. HTML !DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta data-fr-http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>imageGallery</title> <link rel="stylesheet" href="style.css" /> </head> <body> <div class="gallery"> <div class="grid"> <div class="item"> <img src="beautiful-flower.jpg" /> </div> <div class="item"> <img src="beautiful-flowers.jpg" /> </div> <div class="item"> <img src="hill.jpg" /> </div> <!-- Add more image divs as needed --> </div> </div> </body> </html> 2. Style the Gallery With CSS Add CSS styles to create a responsive grid layout for the gallery, and add hover effects to the images. CSS .gallery { max-width: 1200px; margin: 0 auto; } .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); grid-gap: 20px; } .item { position: relative; overflow: hidden; height: 0; padding-bottom: 75%; cursor: pointer; } .item img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; transition: transform 0.3s ease; } .item:hover img { transform: scale(1.2); } Output Let's Continue with the creation by adding more properties. 3. Add Filter Buttons With JavaScript Create filter buttons that allow users to filter the gallery by category. Use JavaScript to add event listeners to the buttons and filter the images based on their class. First, let us edit the HTML file to hold more images. HTML <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta data-fr-http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>imageGallery</title> <link rel="stylesheet" href="style.css" /> </head> <body> <h1 align="center">Simple Image Gallery</h1> <div class="gallery"> <div class="filters"> <button class="filter-btn" data-filter="all">All</button> <button class="filter-btn" data-filter="nature">Nature</button> <button class="filter-btn" data-filter="food">Food</button> </div> <div class="grid"> <div class="item"> <img src="beautiful-flower.jpg" /> </div> <div class="item"> <img src="beautiful-flowers.jpg" /> </div> <div class="item"> <img src="hill.jpg" /> </div> <!-- Add more image divs as needed --> </div> </div> <div class="gallery" style="margin-top: 40px;"> <div class="grid"> <div class="item nature"> <img src="beautiful.jpg" /> </div> <div class="item food"> <img src="food2.jpg" /> </div> <div class="item nature"> <img src="hill.jpg" /> </div> <!-- Add more image divs as needed --> </div> </div> <script src="js.js"></script> </body> </html> Link the JS file as shown and add the code below to your Javascript file. On my end, it saves as js.js. Use JavaScript to add event listeners to the buttons and filter the images based on their class. JavaScript const filterBtns = document.querySelectorAll('.filter-btn'); const gridItems = document.querySelectorAll('.item'); filterBtns.forEach(btn => { btn.addEventListener('click', () => { const filter = btn.dataset.filter; filterItems(filter); setActiveFilterBtn(btn); }); }); function filterItems(filter) { gridItems.forEach(item => { if (filter === 'all' || item.classList.contains(filter)) { item.style.display = 'block'; } else { item.style.display = 'none'; } }); } function setActiveFilterBtn(activeBtn) { filterBtns.forEach(btn => { btn.classList.remove('active'); }); activeBtn.classList.add('active'); } 4. Customize the Gallery as Needed You can customize the gallery by adding more filters, changing the CSS styles, or adding more functionality with JavaScript. Conclusion By following the steps outlined in this tutorial, you can create a responsive and user-friendly gallery that is both visually appealing and functional. With the use of modern web technologies such as CSS Grid and JavaScript, you can create an image gallery that is both easy to maintain and scalable for future enhancements. We hope this tutorial has been helpful in guiding you through the process of building a modern image gallery and that you are now equipped with the skills to create your own unique gallery. Keep practicing and exploring the latest web technologies, and you'll be amazed at what you can create! Happy coding!
Are you exhausted from drowning in an overwhelming flood of print statements while debugging your Python code? Longing for a superior solution to effortlessly identify and rectify common Python errors? Your search ends here with Pdb, the Python debugger that streamlines issue resolution with unparalleled ease. In the ever-growing realm of Python, developers seek dependable tools for swift and efficient code debugging. Enter Pdb, a powerful solution enabling step-by-step code traversal, variable inspection, and strategic breakpoints. With its streamlined interface, Pdb is an indispensable companion for Python developers striving to debug like seasoned pros. Join us as we explore the depths of Pdb's capabilities and unleash your debugging prowess! Setting Up Pdb Using Pdb begins with the installation process. Luckily, Pdb is already integrated into the Python standard library, eliminating the need for separate installation. Nonetheless, for those using older Python versions, manual installation might be necessary. Running Pdb From the Command Line After installing Pdb, unleash its power from the command line by adding this single line of code to your Python file: Python import pdb; pdb.set_trace() This will start the Pdb debugger and pause your code at that point. You can then use various Pdb commands to inspect and modify your code as needed. Running Pdb in Your Code For a more streamlined debugging experience, consider using the Pdb module directly in your code. This allows you to debug without the need for frequent code modifications. Simply import the Pdb module and invoke the set_trace() method at the desired debugging starting point. For instance: Python import pdb def my_function(): pdb.set_trace() # rest of your code here This will start the Pdb debugger at the point where you call the 'set_trace()' method, allowing you to step through your code and identify any errors. Common Python Errors Let's kick things off with syntax errors. These pesky mistakes arise from typos or incorrect keyword usage in your code. Picture this: you write "pritn("Hello, World!")" instead of "print("Hello, World!")" in Python, and boom, a syntax error is thrown. But fear not! Using Pdb, you can identify and resolve syntax errors by stepping through your code until you locate the problematic line. Once found, simply make the necessary edits and resume running your code. Problem solved! Moving forward, let's address name errors—those pesky issues that arise when you attempt to utilize an undefined variable or function. Imagine writing "print(x)" without a prior definition of variable x in Python, resulting in a name error. To resolve such errors using Pdb, execute your code with Pdb and examine the existing variables and functions at the error's occurrence. Once you locate the undefined variable or function, define it and proceed with running your code smoothly. Third, we have type errors. These errors occur when you try to use a variable or function in a way that is not compatible with its data type. For example, if you tried to add an integer and a string together with "1" + 2, Python would throw a type error. To use Pdb to find and fix type errors, simply run your code with Pdb and inspect the data types of the variables and functions that are being used incorrectly. Once you find the incompatible data type, you can correct it and continue running your code. Index errors can occur when attempting to access an index that doesn't exist within a list or string. For instance, if you try to access the third item in a two-item list, Python will raise an index error. To identify and resolve these index errors using Pdb, execute your code with Pdb and examine the accessed indices. Once the out-of-bounds index is identified, make the necessary correction to proceed with running your code. Enter the world of key errors, the elusive bugs that arise when attempting to access nonexistent keys in a dictionary. Picture this: you're digging into a dictionary without defining the key first, and boom! Python throws a key error at you. Fear not, for Pdb is here to save the day. By running your code with Pdb and examining the keys in question, you'll uncover the undefined key culprit. Define it, and voila! Your code can resume its smooth operation. Advanced Pdb Techniques Pdb has several advanced techniques that can make debugging even easier and more effective. Stepping Through Code Pdb's standout feature is its line-by-line code stepping capability, enabling you to precisely track execution and swiftly identify errors. Use "s" to step into functions, "n" to execute the next line, and "c" to continue until breakpoints or code end. Setting Breakpoints One powerful technique in Pdb is the use of breakpoints. These breakpoints pause code execution at specific points, allowing for program state inspection. To set a breakpoint in Pdb, simply use the "b" command followed by the line number or function name. Conditional breakpoints are also possible by specifying a condition in parentheses after the "b" command. Inspecting Variables Unraveling the mysteries of your code is made simpler by leveraging the power of Pdb. With the "p" command, you can effortlessly examine variable values at different program junctures. Moreover, the "pp" command comes in handy for beautifully displaying intricate objects such as dictionaries and lists. Changing Variables In the midst of debugging your code, there might be instances where you wish to alter the value of a variable to observe its impact on the program's behavior. Again, Pdb comes to the rescue, enabling you to accomplish this through the "set" command, specifying the variable name and the desired new value. For instance, executing "set y = 29" would modify the value of "y" to 29. Continuing Execution Once you've pinpointed and resolved a coding error, it's crucial to proceed with execution to uncover any subsequent issues. Pdb simplifies this process through its "c" command, seamlessly resuming execution until the next breakpoint or the code's conclusion. Best Practices Here are some of the best practices you should keep in mind: Don't Overuse Pdb Debugging with Pdb can be tempting, but overusing it is a common mistake. Although it's a powerful tool, relying on it for every small issue can result in cluttered code that's difficult to read and understand. Instead, save Pdb for when it's truly necessary and consider using simpler debugging techniques, such as print statements for simpler issues. Document Your Debugging Process In the realm of code debugging, it's common to lose track of attempted solutions and acquired knowledge. That's why documenting your debugging process is crucial. Maintain a comprehensive log of encountered issues, attempted solutions, and observed outcomes. This log will facilitate picking up where you left off after stepping away from the code and enable seamless sharing of your findings with others if needed. Clean Up Your Code After Debugging After successfully debugging your code, ensure to tidy it up by removing any added Pdb statements or debugging code. This practice not only enhances code readability and comprehension but also prevents the inadvertent inclusion of debugging code in your production codebase. Use Pdb in Conjunction With Other Debugging Tools While Pdb is indeed a powerful tool, it should not be your sole debugging solution. Instead, unlock the full potential by integrating other effective techniques such as log files, unit tests, and code reviews. By combining Pdb with these supplementary tools, you'll gain a comprehensive understanding of your code's inner workings. Conclusion Pdb: The ultimate time-saving and sanity-preserving tool for Python developers. Say goodbye to hours of head-scratching by mastering Pdb's powerful debugging capabilities. But remember, use it wisely alongside other tools, document your process, clean up your code, and avoid excessive reliance. Unleash the power of Pdb today and witness the transformative impact it has on your debugging process. Experience unparalleled efficiency and effectiveness as you conquer Python errors effortlessly. With Pdb as your ally, debug like a true professional.
As a software developer with years of experience working primarily with Java, I found myself intrigued when I recently switched to Python for a new project. The transition prompted me to explore the world of asynchronous programming in various languages, including Java, Python, JavaScript, and Golang. This article is a result of my exploration and personal experience with these languages, aiming to provide insight into asynchronous programming techniques and examples. Asynchronous Programming in Java When I first started programming in Java, I quickly became familiar with the concept of threads. Over time, I found that the Executor framework and CompletableFuture class offered more powerful and flexible ways to handle asynchronous operations. For example, I used the Executor framework to build a web scraper that fetched data from multiple websites concurrently. By using a fixed thread pool, I was able to limit the number of simultaneous connections while efficiently managing resources: Java ExecutorService executor = Executors.newFixedThreadPool(10); for (String url : urls) { executor.submit(() -> { // Fetch data from the URL and process it }); } executor.shutdown(); executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS); Asynchronous Programming in Python Switching to Python, I was initially challenged by the different approaches to asynchronous programming. However, after learning about the asyncio library and the async/await syntax, I found it to be a powerful and elegant solution. I once implemented a Python-based microservice that needed to make multiple API calls. By leveraging asyncio and async/await, I was able to execute these calls concurrently and significantly reduce the overall response time: Python import aiohttp import asyncio async def fetch(url): async with aiohttp.ClientSession() as session: async with session.get(url) as response: return await response.text() async def main(): urls = [...] # List of URLs tasks = [fetch(url) for url in urls] responses = await asyncio.gather(*tasks) asyncio.run(main()) Asynchronous Programming in JavaScript When working with JavaScript, I appreciated its innate support for asynchronous programming. As a result, I have used callbacks, promises, and async/await extensively in various web applications. For example, I once built a Node.js application that required data from multiple RESTful APIs. By using promises and async/await, I was able to simplify the code and handle errors more gracefully: JavaScript const axios = require("axios"); async function fetchData(urls) { const promises = urls.map(url => axios.get(url)); const results = await Promise.all(promises); // Process the results } const urls = [...] // List of URLs fetchData(urls); Asynchronous Programming in Golang During my exploration of Golang, I was fascinated by its native support for concurrency and asynchronous programming, thanks to goroutines and channels. For example, while working on a project that required real-time processing of data from multiple sources, I utilized goroutines and channels to manage resources effectively and synchronize the flow of data: Go package main import ( "fmt" "net/http" "io/ioutil" ) func processSource(url string, ch chan<- string) { resp, err := http.Get(url) if err != nil { ch <- fmt.Sprintf("Error fetching data from %s: %v", url, err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) // Process the fetched data ch <- fmt.Sprintf("Processed data from %s", url) } func main() { sources := [...] // List of data sources ch := make(chan string, len(sources)) for _, url := range sources { go processSource(url, ch) } for range sources { fmt.Println(<-ch) } } Conclusion Asynchronous programming is a crucial aspect of modern application development, and having a deep understanding of its implementation across various languages is invaluable. My experiences with Java, Python, JavaScript, and Golang have taught me that each language has its unique and powerful features for managing asynchronous tasks. By sharing these experiences and examples, I aim to encourage others to embrace asynchrony in their projects, ultimately leading to more efficient and responsive applications.
A couple of weeks ago, I spent the weekend creating another CFP submission helper in the form of a Firefox extension. It was not a walk in the park. To help others who may be interested in doing the same (and my future self), here's my journey. Context I've written multiple posts about my conference submission workflow. To sum up: Everything is based on a Trello board. I created an app that registered a webhook on the board. When I move a conference from one lane to another, it starts or continues a workflow on the app side. I source the board by looking at websites, mainly Papercall and Sessionize, and manually copying conference data on cards. Two automation options are available: Automating conference sourcing Automating a card creation I thought long and hard about the first part. If I automate it, it will create a long list of Trello cards, which I'll need to filter anyway. I concluded that it's better to filter them before. However, I created the card manually by copy-pasting relevant data: name, dates, due date, CFP link, and website. It's precisely what a Firefox extension can help one with. Requirements and Design The user story is pretty straightforward: AS A: Lazy developerI WANT TO: Automatically add CFP data on Trello while browsing a web page on Papercall or SessionizeSO AS: To spend my time doing more fun stuff than copy-paste - My single user story My only requirement is that it needs to work with Firefox. My first idea is a button to trigger the creation, but I don't care much where it is: inside the page as an overlay or somewhere on the browser. In the first case, it should be a JavaScript injected client-side; on the other, a Firefox extension. I chose the second option because I needed to figure out how to achieve the first. I also wanted first to create my extension in Rust with WebAssembly. Spoiler: I didn't. A Simple Firefox Extension I had no clue about writing a Firefox extension, as this was the first time I did write one. My first step was to follow the tutorial. It explains the basics of an extension structure. Then, I followed the second tutorial. It explains how to create a pop-up menu for the extension but not how to interact with the web page. At this point, I decided to learn by doing, a technique that works well for me. A Firefox extension starts with a manifest. Here's the one from the first tutorial, simplified: JSON { "manifest_version": 2, "name": "Borderify", "version": "1.0", "content_scripts": [ { "js": ["borderify.js"] } ] } JavaScript document.body.style.border = '5px solid red'; I found the development feedback loop good. Imagine that you have followed the tutorial and created all the necessary files above. You can go to and click on the "Load Temporary Add-on" button. Then, point to your manifest file. Firefox loads the extension: it's now active. In the above example, the JavaScript from the tutorial adds a red border around every web page. It's useless, we can do better, but it shows how it works. We can change the script to change the color, e.g., from red to green. To make Firefox reload any change, including changes to the manifest, click on the "Reload" button on the temporary extension panel. Interacting With the Extension As I mentioned above, I want a button to trigger the creation of the Trello Card. Firefox allows multiple interaction options: direct trigger or opening of a pop-up window. I don't need to enter any parameter, so the former is enough in my case. Firefox allows multiple places to add buttons: the browser's toolbar, a sidebar, or inside the browser's URL bar. I used the toolbar for no reason other than because it was what the second tutorial demoed. Ultimately, it only changes a little, and moving from one to another is easy. Adding the button takes place in the manifest: JSON "browser_action": { "default_area": "navbar", #1 "default_icon": "icons/trello-tile.svg" #2 } Set the button on the navigation bar. For more details on the button location, please check the documentation. Configure the icon. One can use bitmaps in different formats, but it's so much easier to set an SVG. At this point, everything was fine and dandy. Afterward, I lost many hours trying to understand the different kinds of scripts and how they interact. I'll make it a dedicated section. Scripts, Scripts Everywhere The default language for scripts in extensions is JavaScript. However, depending on their location, they play different roles. Worse, they need to "talk" with one another. Let's start with the content-script I used in the above manifest.json. Content scripts are bound to a web page. As such, they can access its DOM. They run when Firefox loads the page. The script adds a red border around the web page's body in the tutorial. However, we need another kind of script: one to trigger when we click on the button. Such scripts should run along with the extension but can listen to events. They are known as background scripts. Background scripts are the place to put code that needs to maintain long-term state, or perform long-term operations, independently of the lifetime of any particular web pages or browser windows. Background scripts are loaded as soon as the extension is loaded and stay loaded until the extension is disabled or uninstalled, unless persistent is specified as false. You can use any of the WebExtension APIs in the script, as long as you have requested the necessary permissions. - background scripts Let's create such a script. It starts with the manifest - as usual: JSON "background": { "scripts": [ "background.js" ] } We can now create the script itself: JavaScript function foo() { console.log('Hello from background') } browser.browserAction.onClicked.addListener(foo) //1 Register the foo function as an event listener to the button. When one clicks the extension button, it calls the foo function. Debugging the Extension Let's stop for a moment to talk about debugging. I lost several hours because I didn't know what had happened. When I started to develop JavaScript 20 years ago, we "debugged" with alert(). It was not the best developer experience you could hope for. More modern practices include logging and debugging. Spoiler: I didn't manage to get debugging working, so I'll focus on logging. First things first, content scripts work in the context of the page. Hence, logging statements work in the regular console. Background scripts do work in another context. To watch their log statements, we need to have another Firefox developer console. You can open it on the extension panel by clicking the "Inspect" button. Communication Across Scripts Now that we know how to log, it's possible to go further and describe communication across scripts. Here's an overview of the overall flow: Let's change the code a bit so that background.js sends a message: JavaScript function sendMessage(tab) { browser.tabs .sendMessage(tab.id, 'message in from background') .then(response => { console.log(response) }) .catch(error => { console.error(`Error: ${error}`) }) } browser.browserAction.onClicked.addListener(sendMessage) Now, we change the code of content.js: JavaScript browser.runtime.onMessage.addListener((message, sender) => { return Promise.resolve('message back from content') }); Getting the Content So far, we have implemented a back-and-forth flow between the background and the content scripts. The meat is to get content from the page in the content script and pass it back to the background via a message. Remember that only the content script can access the page! The code itself uses the Document API, e.g., document.querySelector(), document.getElementsByClassName(), etc. Specifics are unimportant. The next issue is that the structure of Sessionize and Papercall are different. Hence, we need different scraping codes for each site. We could develop a single script that checks the URL, but the extensions can take care of it for us. Let's change the manifest: JSON "content_scripts" : [{ "matches": [ "https://sessionize.com/*" ], #1 "js": [ #2 "content/common.js", #4 "content/sessionize.js" ] }, { "matches": [ "https://www.papercall.io/*" ], #1 "js": [ #3 "content/common.js", #4 "content/papercall.js" ] }] Match different sites Scripts for Sessionize Scripts for Papercall Code shared on both sites At this point, we managed to get the necessary data and send it back to the background script. The last step is to call Trello with the data. Handling Authentication Credentials Using Trello's REST requires authentication credentials. I want to share the code on GitHub, so I cannot hard-code credentials: I need configuration. We can configure a Firefox extension via a dedicated options page. To do so, the manifest offers a dedicated options_ui section where we can provide the path to the HTML page: JSON "options_ui": { "page": "settings/options.html" } The page can directly reference the scripts and stylesheet it needs. The script needs to: Store credentials in the browser storage on save. Load credentials from the browser storage when the settings page opens. It's pretty straightforward with the provided example. My code is quite similar; it just needs three fields instead of one: JavaScript function saveOptions(e) { browser.storage.sync.set({ //1 listId: document.querySelector('#list-id').value, key: document.querySelector('#key').value, token: document.querySelector('#token').value, }) } function restoreOptions() { browser.storage.sync.get() //1 .then(data => { document.querySelector('#list-id').value = data.listId || '' document.querySelector('#key').value = data.key || '' document.querySelector('#token').value = data.token || '' }, error => { console.error(`Error: ${error}`) }) } document.addEventListener('DOMContentLoaded', restoreOptions) //2 document.querySelector('form').addEventListener('submit', saveOptions) //3 Uses the Firefox storage API Read from the storage when the page loads Save to the storage when the user submits the HTML form We also need to ask the storage permission in the manifest: JSON "permissions": [ "storage" ] We can now store the Trello credentials (as well as the required Trello list id) on the settings page: We can use the same storage API in the Trello calling code to read credentials. At this point, I was happy with my setup. I just added another round-trip from the background to the content to display an alert with Trello's card name and URL. Conclusion It was the first extension I wrote, and though the beginning was challenging, I achieved what I wanted. Now, I can navigate to a Papercall and a Sessionize page, click the extension button, and get the conference on my Trello board. It took me a couple of days and was fun; it was well worth it. I continue working on it to improve it bit by bit. The complete source code for this post can be found on GitHub. To Go Further Content scripts Background scripts webextensions-examples
Managing concurrent access to shared data can be a challenge, but by using the right locking strategy, you can ensure that your applications run smoothly and avoid conflicts that could lead to data corruption or inconsistent results. In this article, we'll explore how to implement pessimistic and optimistic locking using Kotlin, Ktor, and jOOQ, and provide practical examples to help you understand when to use each approach. Whether you are a beginner or an experienced developer, the idea is to walk away with insights into the principles of concurrency control and how to apply them in practice. Data Model Let's say we have a table called users in our MySQL database with the following schema: SQL CREATE TABLE users ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, age INT NOT NULL, PRIMARY KEY (id) ); Pessimistic Locking We want to implement pessimistic locking when updating a user's age, which means we want to lock the row for that user when we read it from the database and hold the lock until we finish the update. This ensures that no other transaction can update the same row while we're working on it. First, we need to ask jOOQ to use pessimistic locking when querying the users table. We can do this by setting the forUpdate() flag on the SELECT query: Kotlin val user = dslContext.selectFrom(USERS) .where(USERS.ID.eq(id)) .forUpdate() .fetchOne() This will lock the row for the user with the specified ID when we execute the query. Next, we can update the user's age and commit the transaction: Kotlin dslContext.update(USERS) .set(USERS.AGE, newAge) .where(USERS.ID.eq(id)) .execute() transaction.commit() Note that we need to perform the update within the same transaction that we used to read the user's row and lock it. This ensures that the lock is released when the transaction is committed. You can see how this is done in the next section. Ktor Endpoint Finally, here's an example Ktor endpoint that demonstrates how to use this code to update a user's age: Kotlin post("/users/{id}/age") { val id = call.parameters["id"]?.toInt() ?: throw BadRequestException("Invalid ID") val newAge = call.receive<Int>() dslContext.transaction { transaction -> val user = dslContext.selectFrom(USERS) .where(USERS.ID.eq(id)) .forUpdate() .fetchOne() if (user == null) { throw NotFoundException("User not found") } user.age = newAge dslContext.update(USERS) .set(USERS.AGE, newAge) .where(USERS.ID.eq(id)) .execute() transaction.commit() } call.respond(HttpStatusCode.OK) } As you can see, we first read the user's row and lock it using jOOQ's forUpdate() method. Then we check if the user exists, update their age, and commit the transaction. Finally, we respond with an HTTP 200 OK status code to indicate success. Optimistic Version Optimistic locking is a technique where we don't lock the row when we read it, but instead, add a version number to the row and check it when we update it. If the version number has changed since we read the row, it means that someone else has updated it in the meantime, and we need to retry the operation with the updated row. To implement optimistic locking, we need to add a version column to our users table: SQL CREATE TABLE users ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, age INT NOT NULL, version INT NOT NULL DEFAULT 0, PRIMARY KEY (id) ); We'll use the version column to track the version of each row. Now, let's update our Ktor endpoint to use optimistic locking. First, we'll read the user's row and check its version: Kotlin post("/users/{id}/age") { val id = call.parameters["id"]?.toInt() ?: throw BadRequestException("Invalid ID") val newAge = call.receive<Int>() var updated = false while (!updated) { val user = dslContext.selectFrom(USERS) .where(USERS.ID.eq(id)) .fetchOne() if (user == null) { throw NotFoundException("User not found") } val oldVersion = user.version user.age = newAge user.version += 1 val rowsUpdated = dslContext.update(USERS) .set(USERS.AGE, newAge) .set(USERS.VERSION, user.version) .where(USERS.ID.eq(id)) .and(USERS.VERSION.eq(oldVersion)) .execute() if (rowsUpdated == 1) { updated = true } } call.respond(HttpStatusCode.OK) } In this example, we use a while loop to retry the update until we successfully update the row with the correct version number. First, we read the user's row and get its current version number. Then we update the user's age and increment the version number. Finally, we execute the update query and check how many rows were updated. If the update succeeded (i.e., one row was updated), we set updated to true and exit the loop. If the update failed (i.e., no rows were updated because the version number had changed), we repeat the loop and try again. Note that we use the and(USERS.VERSION.eq(oldVersion)) condition in the WHERE clause to ensure that we only update the row if its version number is still the same as the one we read earlier. Trade-Offs Optimistic and pessimistic locking are two essential techniques used in concurrency control to ensure data consistency and correctness in multi-user environments. Pessimistic locking prevents other users from accessing a record while it is being modified, while optimistic locking allows multiple users to access and modify data concurrently. A bank application that handles money transfers between accounts is a good example of a scenario where pessimistic locking is a better choice. In this scenario, when a user initiates a transfer, the system should ensure that the funds in the account are available and that no other user is modifying the same account's balance concurrently. In this case, it is critical to prevent any other user from accessing the account while the transaction is in progress. The application can use pessimistic locking to ensure exclusive access to the account during the transfer process, preventing any concurrent updates and ensuring data consistency. An online shopping application that manages product inventory is an example of a scenario where optimistic locking is a better choice. In this scenario, multiple users can access the same product page and make purchases concurrently. When a user adds a product to the cart and proceeds to checkout, the system should ensure that the product's availability is up to date and that no other user has purchased the same product. It is not necessary to lock the product record as the system can handle conflicts during the checkout process. The application can use optimistic locking, allowing concurrent access to the product record and resolving conflicts during the transaction by checking the product's availability and updating the inventory accordingly. Conclusion When designing and implementing database systems, it's important to be aware of the benefits and limitations of both pessimistic and optimistic locking strategies. While pessimistic locking is a reliable way to ensure data consistency, it can lead to decreased performance and scalability. On the other hand, optimistic locking provides better performance and scalability, but it requires careful consideration of concurrency issues and error handling. Ultimately, choosing the right locking strategy depends on the specific use case and trade-offs between data consistency and performance. Awareness of both locking strategies is essential for good decision-making and for building robust and reliable backend systems.
In this series of simulating and troubleshooting performance problems in Scala, let’s discuss how to simulate thread leaks. java.lang.OutOfMemoryError: unable to create new native thread will be thrown when more threads are created than the memory capacity of the device. When this error is thrown, it will disrupt the application’s availability. Video: To see the visual walk-through of this post, click below: Scala Sample Thread Leak Program Here is a sample Scala program, which will generate java.lang.OutOfMemoryError: unable to create new native thread Scala package com.yc import java.lang.Thread.sleep class ThreadLeakApp { } object ThreadLeakApp { def main(args: Array[String]): Unit = { System.out.println("ThreadApp started") while (true) { new ForeverThread().start() } } class ForeverThread extends Thread { override def run(): Unit = { while (true) { sleep(100) } } } } You can notice that the sample program contains the ThreadLeakApp class. This class has a start() method. In this method, ForeverThread is created an infinite number of times because of the while (true) loop. In the ForeverThread class there is the run() method. In this method, thread is put to continuous sleep, i.e., thread is repeatedly sleeping for 100 milliseconds again and again. This will keep the ForeverThread alive always without doing any activity. A thread will die only if it exits the run() method. In this sample program run() method will never exit because of the never-ending sleep. Since the ThreadLeakApp class keeps creating ForeverThread infinitely and it never terminates, very soon several thousands of ‘ForeverThread’ will be created. It will saturate memory capacity, ultimately resulting in java.lang.OutOfMemoryError: unable to create new native thread problem. How To Diagnose java.lang.OutOfMemoryError: unable to create new native thread? You can diagnose the OutOfMemoryError: unable to create new native thread problem either through a manual or automated approach. Manual Approach In the manual approach, you need to capture thread dumps as the first step. A thread dump shows all the threads that are in memory and their code execution path. You can capture a thread dump using one of the 8 options mentioned here. But an important criterion is: You need to capture thread dump right when the problem is happening (which might be tricky to do). Once the thread dump is captured, you need to manually import the thread dump from your production servers to your local machine and analyze it using thread dump analysis tools like fastThread, and samurai. Automated Approach On the other hand, you can also use yCrash open source script, which would capture 360-degree data (GC log, 3 snapshots of thread dump, heap dump, netstat, iostat, vmstat, top, top -H,…) right when the problem surfaces in the application stack and analyze them instantly to generate root cause analysis report. We used the automated approach. Below is the root cause analysis report generated by the yCrash tool highlighting the source of the problem. From the report, you can notice that yCrash points out that 2608 threads are in TIMED_WAITING state, and they have the potential to cause OutOfMemoryError: unable to create new native thread problem. Besides the thread count, the tool is also reporting the line of code, i.e., com.yc.ThreadLeakApp$ForeverThread.run(ThreadLeakApp.scala:31) in which all the 2608 threads are stuck. Equipped with this information, one can quickly go ahead and fix the java.lang.OutOfMemoryError: unable to create new native thread problem.
Web3, blockchain technology, and cryptocurrency are all fascinating topics. The technology, applications, ecosystem, and the impact on society are all moving at incredible speeds. In this article, we will talk about learning web3 development from the point of view of a seasoned developer who is a total web3 newbie. We will look at the prerequisites for web3 development, use Python to access the blockchain via Infura, web3’s top API service, and go over a simple project for managing a wallet. How To Get Started Even though I’ve been coding since the late 1990s, I am truly a complete beginner in the web3 world. I’m no expert, so I won’t try to explain the fundamentals. There are a lot of great content guides and tutorials out there. I suggest starting with the Infura documentation, which is very comprehensive as well as comprehensible. There is also a community discord if you prefer a more interactive style of learning. Anyway, let’s start with some basics. We need an Infura account, a wallet to store our cryptocurrency, and we need some money to play with. Opening an Account With Infura Infura is a provider of blockchain APIs and developer tools. This means that if you want to access the blockchain, you don’t need to run a node yourself. Instead, you just access a friendly API, and Infura does all the heavy lifting for you. Infura is free and totally secure, as it doesn’t store your private keys and doesn’t have the ability to modify your transactions or replay them multiple times. You can open an account for free, and no credit card is required. Creating an Infura project A project is where things become interesting. Each project has an API key, which identifies it and allows you to use Infura. Follow the instructions here. Setting up a Crypto Wallet The next piece of the puzzle is a crypto wallet. This is where the rubber meets the road. In the blockchain environment, crypto wallets hold balances that are fully controlled by a set of digital keys. There is no such thing as personal ownership of an account. Each account has a public key — which is visible in the blockchain — and a private key that controls the account. Whoever holds a private key has total control of an account. You may also manage multiple accounts as a set of private keys. Wallets give you a secure way to manage your accounts/private keys as well as other benefits such as convenience, portability, and compatibility. Infura recommends MetaMask. You can install MetaMask as a browser extension. Great, we have a crypto wallet. Now let’s talk money! Getting Some Money The blockchain is not free. Crypto economics are way above my pay grade, but in simple terms, each transaction costs money. If you want to play on the blockchain, you need funds. Luckily for developers, there are test networks that let you get test money for free. You can’t exchange it for real money, but you can use it for developing and testing web3 applications. Speaking of which, there are different types of networks. Here, we will focus on the Ethereum blockchain. In this project, I used the testnet Sepolia. You can get test ETH from Sepolia by going to a faucet site. (ETH is Ethereum’s native cryptocurrency. You use it to pay for transactions on the Ethereum network. Test ETH is a necessity for Ethereum development.) A faucet site can transfer a small amount of testnet ETH to your wallet. Some faucets will require you to do some mining to earn your money, and some will gift you some money periodically. I had success with the ConsenSys Sepolia faucet which gives out .5 Sepolia ETH per day to an address. OK. We covered all the basics. Let’s check out the Infura API. Accessing the Infura API Infura provides a JSON-RPC API over HTTPS (REST) and WebSockets. It has several categories and you can read all about them here. Additionally, the Infura API supports multiple different networks. Each network has its own https endpoint that you use as a base URL when accessing the API. Here are the endpoints for Ethereum: Mainnet Ethereum Mainnet JSON-RPC over HTTPS— https://mainnet.infura.io/v3/<API-KEY> Ethereum Mainnet JSON-RPC over WebSocket— wss://mainnet.infura.io/ws/v3/<API-KEY> Goerli Ethereum Goerli Testnet JSON-RPC over HTTPS— https://goerli.infura.io/v3/<API-KEY> Ethereum Goerli Testnet JSON-RPC over WebSocket—wss://goerli.infura.io/ws/v3/<API-KEY> Sepolia Ethereum Sepolia Testnet JSON-RPC over HTTPS—https://sepolia.infura.io/v3/<API-KEY> Ethereum Sepolia Testnet JSON-RPC over WebSocket—wss://sepolia.infura.io/ws/v3/<API-KEY> Just to test that we can access the API, let’s get our wallet balance using curl. I stored the Infura API key and API key secret in environment variables called simply: INFURA_API_KEY and INFURA_API_KEY_SECRET. I also stored the public key of the MetaMask wallet in an environment variable called SEPOLIA_ACCOUNT. The curl command is: $ curl --user ${INFURA_API_KEY}:${INFURA_API_KEY_SECRET} \ -X POST \ -H "Content-Type: application/json" \ --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["'"${SEPOLIA_ACCOUNT}"'","latest"],"id":1}' \ https://sepolia.infura.io/v3/${INFURA_API_KEY} a{"jsonrpc":"2.0","id":1,"result":"0x1d7e6e62f1523600"} As you can see, I have a HUGE balance of 0x1d7e6e62f1523600!!!! But no need to get too excited: the balance units are Wei. One ETH is equal to 10¹⁸ Wei. If we crunch the numbers, we can see that I have a little more than 2 ETH in my account. Of course, this is all testnet money. Note that I didn’t have to use my account’s private key to check my balance. Anyone can check the balance of any account in the blockchain. The balance of any account is not sensitive information. However, the identity of the account and the person that holds the private key is sensitive and confidential. All right… we had our fun with hitting the Infura API directly. Let’s do some coding. Web3 Development With Python The web3 ecosystem supports many programming languages. Infura APIs can be accessed from popular libraries in JavaScript (web3.js and ethers.js), Golang, and Python (web3.py). Choose Your Weapon: web3.py Although most of coding these days is in JavaScript/Node.js and Ruby, Python is great when learning a new topic. The web3.py library seems powerful, mature, and well-documented. So I decided to go with it. Choose Your Target: Wallet Manager The web3 world can be overwhelming: transactions, smart contracts, IPFS, DAO (decentralized autonomous organizations), defi (decentralized finance), and NFTs. I decided to pick a simple concept of a wallet manager for this web3 test project. The wallet manager is kind of a “hello web3 world” project because all it does is get your balance and send some money to a destination account. Since I got my money from a Sepolia faucet, I decided to give back by sending it some of the funds. Let’s check out the code. The web3-test dApp (Decentralized App) The code is available on Github here. (Special thanks to the-gigi!) I used Poetry to scaffold the application. The README provides step-by-step instructions to set up everything. Before we dive into the code, let’s run the program and see what happens: $ poetry run python main.py balance before transaction: 2.1252574454 send 20,000 gwei to 0xea4d57b2dd421c5bfc893d126ec15bc42b3d0bcd (Sepolia faucet account) balance after transaction: 2.125184945399832 As you can see, my balance was initially a little over 2 testnet ETH. Then, I sent 20,000 Gwei (which is 20 billion Wei) to the Sepolia faucet account that I got the money from in the first place. As you can see, it barely made a dent in my balance. This just shows what a tiny unit the Wei is. The code is pretty simple. There is just a single file called main.py. The file contains a main() function and a WalletManager class. Let’s start with the main() function, which is the entry point to the program. The main() function takes no command-line arguments or configuration files. Everything is hard-coded for simplicity. First, the function instantiates the WalletManager class, then it defines the public key of the Sepolia faucet account. Now, we get to action. The function obtains the balance of the wallet by invoking the get_balance() method of WalletManager, then it passes the requested unit (ether), and displays it on screen. Next, the function invokes the send_eth() method to send 20,000 Gwei to the target account. Finally, it gets and displays the balance again after the money has been sent. def main(): wm = WalletManager() sepolia_faucet_account = wm.w3.toChecksumAddress('0xea4d57b2dd421c5bfc893d126ec15bc42b3d0bcd') balance = str(wm.get_balance('ether')) print(f'balance before transaction: {balance}') print(f'send 20,000 gwei to {sepolia_faucet_account} (Sepolia faucet account)') wm.send_eth(sepolia_faucet_account, 20000, 'gwei') balance = str(wm.get_balance('ether')) print(f'balance after transaction: {balance}') if __name__ == '__main__': main() Let’s look at the WalletManager class. It has four methods: __init__(), __create_web3_instance() get_balance() sent_eth() Method 1: __init__() Let’s look at them one by one. The __init__()method, which is the constructor, first calls the __create_web3_instance() method and stores the result in a variable called w3. Then __init__() extracts a couple of environment variables and stores them. It continues to compute a couple of gas fees (which is the fuel the blockchain is running on) and the rewards that are given to the people that validate transactions. If you want to know more about gas and fees, read this. It also stores the chain ID, which identifies the Sepolia testnet (in this case). We will need this ID later when sending transactions to the Sepolia testnet. import base64 import os import web3 class WalletManager: def __init__(self): self.w3 = self.__create_web3_instance() self.account = os.environ['SEPOLIA_ACCOUNT'] self.account_private_key = os.environ['METAMASK_PRIVATE_KEY'] self.max_fee_per_gas = self.w3.toWei('250', 'gwei') self.max_priority_fee_per_gas = self.w3.eth.max_priority_fee self.chain_id = self.w3.eth.chain_id Method 2: __create_web3_instance() Let’s see what happens inside the __create_web3_instance() method. __create_web3_instance() is a static method because it doesn’t need any information from the WalletManager class. It gets the Infura API key and API key secret from the environment, and then it encodes them into a basic authentication token. It prepares the proper endpoint for our project on the Sepolia testnet, and then it instantiates a web3 object from the web3 library with all the information. This object will allow us to invoke the Infura API via a convenient Python interface (instead of constructing JSON-RPC requests and parsing the results). @staticmethod def __create_web3_instance(): infura_api_key = os.environ['INFURA_API_KEY'] infura_api_key_secret = os.environ['INFURA_API_KEY_SECRET'] data = f'{infura_api_key}:{infura_api_key_secret}'.encode('ascii') basic_auth_token = base64.b64encode(data).strip().decode('utf-8') infura_sepolia_endpoint = f'https://sepolia.infura.io/v3/{infura_api_key}' headers = dict(Authorization=f'Basic {basic_auth_token}') return web3.Web3(web3.HTTPProvider(infura_sepolia_endpoint, request_kwargs=dict(headers=headers))) Method 3: get_balance() Alright, next is the get_balance() method. It is an extremely simple method. It just invokes the w3.eth.get_balance() method of the web3 object and passes our account. The eth.get_balance() always returns the result in Wei, which is often too small. Our method provides us with the option to convert the result to another denomination like Gwei or Ether. It does it by invoking the w3.fromWei() method provided again by our web3 instance. Note that we didn’t have to use our private key to check the balance. balance = self.w3.eth.get_balance(selpytf.account) if unit != 'wei': return self.w3.fromWei(balance, unit) Method 4: send_eth() Last but not least is the send_eth() method. There is a lot going on here, so let’s break it into multiple blocks. First, send_eth() converts the amount to send to Wei (if necessary), and then it gets the transaction count of the account and stores it as nonce. The nonce allows us to overwrite pending transactions if needed. def send_eth(self, target_account, amount, unit='wei'): if unit != 'wei': amount = self.w3.toWei(amount, unit) nonce = self.w3.eth.get_transaction_count(self.account) Next, it constructs a transaction object. The most important fields are the from (the wallet’s account), the to (the transaction’s recipient) and the value (how much to send). Then, there are the fields that determine how much gas to pay. (The more gas, the more likely that validators will include the transaction,) The chainId identifies the network to run this transaction against and a couple of administrative fields (empty data and type). tx = {'nonce': nonce, 'maxFeePerGas': self.max_fee_per_gas, 'maxPriorityFeePerGas': self.max_priority_fee_per_gas, 'from': self.account, 'to': target_account, 'value': amount, 'data': b'', 'type': 2, 'chainId': self.chain_id} tx['gas'] = self.w3.eth.estimate_gas(tx) OK. We have a transaction, so can we send it? Not so fast. First, we need to sign it with our private key. This is what prevents other people from transferring money out of our account. Signing the transaction with the private key allows validators to confirm that the private key corresponds to the public key of the account. signed_tx = self.w3.eth.account.sign_transaction(tx, self.account_private_key) Now we can send the transaction as a raw transaction. This means that Infura never sees our private key, and it can’t change our transaction or direct our transfer to a different account. This is the magic of the blockchain in action. After sending the transaction, we get back a hash code and wait for the transaction to complete. If the status of the result is 1, then all is well. If not, the code raises an exception. tx_hash = self.w3.eth.send_raw_transaction(signed_tx.rawTransaction) result = self.w3.eth.wait_for_transaction_receipt(tx_hash) if result['status'] != 1: raise RuntimeError('transaction failed: {tx_hash}') That’s all it takes to interact in a very basic, yet secure way with the blockchain. Conclusion: Start Your Web3 Journey With Infura Diving headfirst into the world of web3 can be intimidating, even for an experienced programmer. We’ve learned a lot; mostly, we’ve learned that we have a lot more to learn! Infura made it easy by providing a solid API, great guidance, and strong integration with other components of the ecosystem, like MetaMask and the web3.py library. If you are in a similar position and want to learn web3 development — or even want to start a web3 career — I highly recommend starting with Infura. See where the journey takes you!
Web development, like most technologies, moves in waves and cycles. Static websites were all we had in the beginning. But, pretty soon, developers were hacking together the first server-generated sites thanks to Perl and PHP. This was the advance that would eventually kickstart frameworks like Laravel, Django, or Rails. Mobile devices would come to change how people consume the web. So long server-generated websites, hello client-rendered applications. The next wave brought frameworks that could give users a more app-like experience—without reloads—like React or AngularJS. While single-page applications provided a smoother experience, they have their drawbacks. Namely, longer page loads caused by all the extra JavaScript that has to be parsed and executed. Not to mention all the work it took to optimize for search engines. Astro is a prime example of the current wave we have been in since Next.js, taking us full circle: a web framework that combines server and client rendering to get the best of both worlds. What Is Astro? Astro is an open-source framework for generating web applications on top of popular UI frameworks like React, Preact, Vue, or Svelte. An Astro page is composed of several independent components. To improve load times, Astro strips away all JavaScript and prerenders pages in the server unless developers mark a component as interactive, in which case, Astro will send the minimum amount of JavaScript required for interactivity. Astro favors generating static and server-rendered sites without JavaScript in the browser. Developers can opt-in to client-side rendering for given routes or parts of the page. Thanks to this strategy, Astro pages load quickly, as no JavaScript needs to execute for the first render. In a process called hydration, Astro will “pour” JavaScript into components to make them dynamic. Getting Started With Astro To get started with Astro, install Node version 16.12.0 or higher and run the following command. Follow the on-screen wizard and choose to create an empty project when prompted: $ npm create astro@latest astro v1.9.1 Launch sequence initiated. ✔ Where would you like to create your new project? … awesome-website ✔ How would you like to setup your new project? › an empty project ✔ Template copied! ✔ Would you like to install npm dependencies? (recommended) … yes ✔ Packages installed! ✔ Would you like to initialize a new git repository? (optional) … yes ✔ Git repository created! ✔ How would you like to setup TypeScript? › Relaxed ✔ TypeScript settings applied! next Liftoff confirmed. Explore your project! Next, you can start the website in developer mode by entering the directory of the project you just created and running: npm run dev and visiting http://localhost:3000. Pages and Routes The interesting stuff in Astro happens inside the src folder. Checking what’s there, we see a single directory called pages with an index.astro file. Astro pages are a mix of HTML, Javascript, or TypeScript. This is the default index.astro: --- --- <html lang="en"> <head> <meta charset="utf-8" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="viewport" content="width=device-width" /> <meta name="generator" content={Astro.generator} /> <title>Astro</title> </head> <body> <h1>Astro</h1> </body> </html> You may have noticed that Astro files start with fences delineated with ---. Whatever code we put inside these fences is executed on the server and prerendered before serving the page. Below the frontmatter, we find the content for this route, an augmented HTML form that allows for variables. We can, for example, define a variable in the frontmatter and use it in HTML like this: --- // src/pages/index.astro const title = "Astro"; --- <html lang="en"> <head> <meta charset="utf-8" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="viewport" content="width=device-width" /> <meta name="generator" content={Astro.generator} /> <title>{title}</title> </head> <body> <h1>{title}</h1> </body> </html> Astro uses a file-based routing, so every file in the pages folder is mapped to a route in the website. For example, if we create a file called greetings.astro, we should see its contents at http://localhost:3000/greetings: --- const greeting = "Hello, world!"; --- <html lang="en"> <head> <meta charset="utf-8" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="viewport" content="width=device-width" /> <meta name="generator" content={Astro.generator} /> <title>Astro</title> </head> <body> <h1>{greeting}</h1> </body> </html> In addition to .astro files, Astro can parse Markdown, MDX, JSX JavaScript, and TypeScript files. For instance, if we want to write a blog post in Markdown, we create a post.md file under the pages folder. Visiting the route will make Astro convert it into HTML on the fly: --- title: 'Learning Astro' pubDate: 2023-01-10 description: 'A post written in Markdown.' author: 'Tommy' --- # Learning Astro This Markdown file should be rendered as HTML when I visit http://localhost:3000/post Components Astro components are *.astro files with reusable code and HTML. We can use components to write elements like headers, footers, navigation bars, buttons, and forms—anything that can be expressed as HTML can constitute a component. Let’s create our first component in src/components/Header.astro: --- // src/components/Header.astro --- <meta charset="utf-8" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="viewport" content="width=device-width" /> <meta name="generator" <title>Astro</title> Once defined, we can import it to any page (or other components) and use it like this: --- import Header from "../components/Header.astro"; --- <html lang="en"> <head> <Header /> </head> <body> </body> </html> Astro components are no different from pages. Any code defined between fences is executed on the server. JavaScript is stripped out before sending the content to the browser. Layouts Layouts are used to refine reusable UI structures. They are technically components, so the syntax stays the same. Let’s replace the content of index.astro with a layout: --- // src/pages/index.astro import SiteLayout from "../layouts/SiteLayout.astro"; --- <SiteLayout></SiteLayout> As you can see, layouts are stored in the src/layouts folder by convention. Layouts, like components, can include other components. Here, we have extracted the structure in index.astro and added a Footer component: --- // src/layouts/SiteLayout.astro import Header from "../components/Header.astro"; import Footer from "../components/Footer.astro"; --- <html lang="en"> <head> <Header /> </head> <body> <Footer /> </body> </html> Props and Slots So far, our website has been completely static. To pass data between pages and components, we need to understand how props and slots work. Components and layouts can define and accept props (short for properties) via the global Astro.props. Values passed through props are accessible to the component before rendering. We can read props in our component like this: --- // src/components/Header.astro const { title } = Astro.props; --- <meta charset="utf-8" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="viewport" content="width=device-width" /> <meta name="generator" <title>{title}</title> The value of title can be supplied when the component is called, which, in the following example, happens through the SiteLayout layout: --- // src/layouts/SiteLayout.astro import Header from "../components/Header.astro"; import Footer from "../components/Footer.astro"; --- <html lang="en"> <head> <Header title = "Welcome my Astro Blog!" /> </head> <body> <Footer /> </body> </html> Note: you need spaces surrounding the equal sign, i.e., title="Hello" is NOT correct. Instead, it should be: title = "Hello". Slot elements create placeholders for content to be injected later. To see how it works, we can add a <slot /> element in src/layouts/SiteLayout.astro: --- // src/layouts/SiteLayout.astro import Header from "../components/Header.astro"; import Footer from "../components/Footer.astro"; --- <html lang="en"> <head> <Header title = "Welcome my Astro Blog!" /> </head> <body> <slot /> <Footer /> </body> </html> Now, the HTML inside <SiteLayout> is injected into the point where the slot is located: --- // src/pages/index.astro import SiteLayout from "../layouts/SiteLayout.astro"; --- <SiteLayout> <p>This content is rendered in the slot</p> </SiteLayout> Nesting components, layouts, props, and slots give us the flexibility to create reusable UI files across the website. Islands and Hydration Up to this point, we have not shipped any JavaScript to the user; everything is prerendered and served as pure HTML+CSS. How do we make Astro send JavaScript to the browser? For that, we need to understand the islands architecture. The island architecture pattern aims to reduce the amount of JavaScript needed browser-side. Less JavaScript means less data sent and less computational power required on the user’s device. An island is an autonomous component that bundles HTML, CSS, and—optionally—JavaScript. In the islands pattern, a page is made up of several independent islands. The islands architecture allows combining static HTML, server-rendered content, and interactive client-rendered components on one page without conflicts. Each island is prerendered, so there is no interactivity right after the page loads. Once the initial page is ready, the islands are converted into interactive content in a process called hydration. Hydration is a technique that converts static content delivered via static hosting or server-side rendering into a dynamic page by attaching event handlers to the HTML elements. The first contentful paint happens right after all the HTML has been sent to the browser, which typically happens very quickly. The browser then requests and executes all the client-side JavaScript needed to make the page fully interactive. Using Islands An example showing how Astro implements islands is in order. Let’s first add a UI integration to the project. The following command installs @astrojs/preact and preact: $ npx astro add preact Let’s create a simple button to test the integration: // src/components/MyButton.jsx export default function MyButton() { const clicked = () => { console.log('Hello!') }; return ( <div> <button style={{ color: 'purple' } onClick={clicked}>Click me</button> </div> ) } As usual, Astro will try to strip away any JavaScript. So, nothing would happen if we instantiated the component with <MyButton />. We need to tell Astro we want this component treated as an island and hydrated accordingly by adding the template directive client:load: --- import MyButton from "../components/MyButton.jsx"; --- <html lang="en"> <body> <MyButton client:load /> </body> </html> Clicking the button should print “Hello!” in the browser console. The client directive caused Astro to hydrate the component. There are five levels of hydration with different priorities: client:load hydrates the component as soon as possible. client:idle hydrates the component when the page is done loading. Useful for low-priority components that don’t need immediate interactivity. client:visible={string} hydrates the component as soon as it appears in the viewport. client:media={string} takes a CSS query as an argument and loads the component as soon as it’s fulfilled. client:only skips HTML rendering entirely and renders the component in-browser. Conclusion The popularity of this project has been nothing short of astronomical: in the first five months since the Astro 1.0 release, the project has amassed over 25,000 stars on GitHub. The success of Astro is not accidental. The Astro team has made a web framework that offers great ergonomics for developers and fast-loading websites for users, even if they are on low-power devices or slow connections. Thanks for reading, and happy building!
If you've ever implemented a Java project using a mainstream build system such as Ant, Maven, or Gradle, you've probably noticed that you need to use extra language to describe how to build your project. While this may seem appealing for basic tasks, it can become trickier for more complicated ones. You need to learn a specific soup of XML, write verbose configurations, or write Kotlin DSLs that are intertwined with complex tooling. If you've gone further by writing pipelines for deploying and managing releases, you've probably had to write shell or Groovy scripts to be used in your CI/CD tools. While this may be okay for simple tasks, it can become cumbersome when dealing with complexity. You'd prefer to use all your knowledge and tooling when producing regular code, such as modeling, refactoring, and run/debug in IDEs. This is where JeKa comes in. JeKa is a very thin tool that allows you to execute arbitrary Java source code from the command line or within your IDE. While this may not seem like a big deal at first glance, this capability enables you to: Write any arbitrary script using plain Java code, run and debug it in an IDE, and invoke arbitrary public methods so you can host many scripts in a single class. Invoke this code from the command line or any CI/CD tool without needing to compile it. JeKa handles the compilation for you. Simply use any library available in the Java ecosystem in your scripts. Just declare dependencies in annotations, and JeKa will resolve them behind the scenes. With this capability, you can get rid of cryptic shell scripts and implement powerful and portable scripts without needing additional knowledge. The second stage of JeKa is the utilities it embeds. When writing scripts, you can use any libraries, but JeKa also bundles some utilities that are frequently needed when implementing automation tasks, such as dealing with file sets and zip files, Git, launching OS processes synchronously and retrieving results, Java compilation/testing, Maven dependency/repo management, full JVM project build models, and XML handling. These utilities can help you implement CI/CD pipelines or even build/test entire Java projects. The last stage consists of a plugin and parameterization mechanism that allows JeKa to be a first-class citizen in the build tool space. Each plugin provides methods and configurations to integrate external technology with a minimum of effort or no typing. Currently, there are plugins for JVM projects, Node.js, Spring Boot, SonarQube, JaCoCo, Kotlin, Protocol Buffers, and Nexus repositories. With all these capabilities, JeKa lets you implement an entire Java project with automated delivery using a single language for everything. This language can be Java, or it can be Kotlin, as JeKa provides the same capabilities for both. Additionally, an IntelliJ plugin exists to improve the user experience with JeKa. For a better understanding, check out this GitHub repository that demonstrates numerous projects built with Jeka. Through this, you'll gain insights into how Jeka can be utilized to build projects with popular technologies like Spring Boot, Kotlin, Node.js, SonarQube, and JaCoCo. Jeka also provides detailed documentation describing exactly how it works. You won't be left to your own devices using it. What do you think about this initiative? Do you think JeKa can ease the full development-delivery cycle?
To put it in simple terms, an HTML, or web forms, are referred to as web elements that are designed to enable users to put in their information, which may include their names, age, gender, credit card number, etc., which is then sent to a server for processing. Web forms are very useful and are now a very important aspect of web development. Imagine having to travel to a foreign country just to fill out a form because you want to apply for a course in their university. Since every modern university has a website with a form, students can sit in the comfort of their homes and apply within their convenient time, saving them the time to visit the school in person. Next, the school collects this information to decide if the candidate is qualified to study at their university. Web forms are not limited to schools only, businesses, such as banks and e-commerce, to mention a few, use web forms to collect information from their customers. This helps them decide how to serve the needs of their customers better. This is exactly what web forms are designed to do—collect information for processing. In this tutorial on CSS Forms, we will take a closer look at how to style forms with CSS and much more. Prerequisites for Styling CSS Forms By the end of this tutorial, you will be in a position to build a form in HTML that is styled using CSS. However, a basic knowledge of HTML and CSS is required to understand this article. Here is a sample of the finished project of what we’ll be building. Here is the link to CodePen for this styling CSS Form project’s source code. Creating HTML Boilerplates Let’s start by creating the website boilerplates (that is, the HTML code structure for the website). This contains the head and body tags, as seen below: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta data-fr-http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>How to style forms with CSS: A beginner's guide</title> <link rel="stylesheet" href="main.css"> </head> <body> </body> </html> After creating our HTML boilerplate, save it as an index.html file. I am using VS Code but you can use any IDE of your choice. Creating the Necessary HTML Tags Now, let’s create the necessary HTML tags for our styling CSS Forms project: class="site__container"> <main class="hero__images"> <main class="card__wrapper"> <!-- background for the form --> <section class="card__forms"> <!-- Wrapper for all items of the box --> <section class="items__wrapper"> <div class="site__logo">MS</div> <div class="sign__caption"> <p>Signin for home delivery service</p> </div> <div class="user_id"> <!-- user id options for username and password --> <input type="text" name="Username" placeholder="Username"> <input type="password" name="Password" placeholder="Password"> </div> <div class="checkbox__wrapper"> <!-- Input field for checkbox and forget password --> <input type="checkbox" name="checkbox"> <label for="checkbox">stay signed in</label> <a href="#">Forget Password?</a> </div> <div class="btn__wrapper"> <!-- Sign in button --> <button class="btn__signin">sign in</button> </div> <div class="signup__option"> <!-- Sign up option for new users --> <p>Don't have an account yet? <a href="#">Sign Up!</a></p> </div> </section> </section> </main> </main> </div> </body> From the code sample above, let’s look at what each tag is supposed to do based on the class names assigned to them: site__container: This class is assigned to a div tag that wraps around every other tag within our HTML tags. hero__images: This class is assigned to the main tag. This tag is where our hero image will be assigned using CSS. card__wrapper: This class is assigned to another main tag nested inside the hero__image tag. This tag wraps around all tags that make up our web form. card__forms: This class is assigned to the section tag, which is the main tag for our web form Items__wrapper: This tag wraps around the div, input, button, and link tags, which are items within the web form. site__logo: This is the site logo. sign__caption: This tag helps inform the user why they should sign up/sign in using the web form. user_id: This wraps around the input tag where the user has to enter their username and password. checkbox__wrapper: This wraps around the input, a (anchor), and labels tag. Here, we ask the user if they would like their user id to be saved so they don’t have to retype them later when they visit the site by clicking the checkbox. We also ask if they have a forgotten password that needs to be recovered. btn__wrapper: This wraps around the main button of the form. This is the button the user clicks on that helps them sign into the site. signup__option: This tag wraps around the paragraph tag and a link tag. Here, we provide an option for new users who don’t have an account to signup. Now that we have the HTML boilerplate setup, save it, and run it on your favorite browser. The code in this CSS Forms tutorial is run using Google Chrome. Browser Output Your code should look like this. You will notice how plain and simple the website is from our browser output. This is because we have not added the CSS yet. In the next section of this tutorial, we’ll talk about this. Styling Common Form Elements With CSS Form elements are some of the most common elements on a website. Every site must have these elements, from login forms to search boxes and buttons, to be functional. These elements are sometimes overlooked in design and styling, which may cause them to blend into each other, making your site’s UI look dull. A good way to avoid this is by using CSS to change the appearance of form elements such as text fields and buttons. Here’s how you can style common CSS form elements: 1. In your Visual Studio Code, create a new file and name it main.css. This is going to be the CSS file. Notice from our HTML file that, in the head tag, we have a link tag that points to main.css. This link tag helps us link together the HTML and CSS files. Any changes to the HTML will affect the CSS file and vice versa. 2. Let’s add the relevant CSS code in main.css so we can style the boring page we created earlier using HTML. 3. Your editor should open. Now, let’s write some CSS. Applying Universal Selector Universal selector is a CSS concept that lets you define styles once and reuse them across the entire website. It means you need to define only that “one thing” once, and then you can use it on other pages. This saves us a lot of time and makes the code more maintainable. Type and run the code below for your CSS Forms project: *, *::after, *::before { padding: 0; margin: 0; box-sizing: border-box; } From the CSS code above, we use a CSS universal selector to target all the elements on the webpage. We added a padding 0px, margin 0px and box-sizing of the border-box. This helps remove all the white spaces on the webpage so we don’t have unnecessary white spaces interfering when styling CSS Forms. Applying Viewport Width (VW) and Viewport Height (VH) Applying viewport width (vw) and viewport height (vh) are new properties available in CSS3 and have quite a few uses. By default, the vw unit is equal to 1% of the containing element’s width. The same goes for vh. Using these properties, you can do some cool things with your website: .site__container { width: 100vw; height: 100vh; } We target a div tag with a class of .site__container and we assign a width and height of 100vw and 100vh to both, respectively. This helps size our webpage’s viewport to take the browser’s full width and height. You will not see any effect when you refresh your browser since other HTML tags have not been given specific sizing or styling. Applying Hero Image The hero image is a common element in blog design. It’s a large, eye-catching image that spans the full width of the page and often a bit of the page’s height. It is usually used to draw initial attention to an article or page and as an anchor point for future articles or pages within that site section. A hero image can also highlight content, such as images, videos, or other interactive elements, by making it the central point of focus on the page: .hero__images { height: 100%; background-image: url("./delivery-man.jpg"); background-repeat: no-repeat; background-size: cover; background-position: center; } Browser Output From the CSS code above, we assigned a height of 100% to the class of hero__images. This helps the hero__images class inherit the same height value set to the direct parent, which is 100vh. This helps the background image used to occupy the browser viewport, and then we set a background-image. We also added a background-repeat of no-repeat to prevent it from repeating, a background-size of cover, which helps set the image to cover the entire viewport, and a background-position of center, which helps center the image within the viewport or container. Centering the Form With Flexbox Centering the form with CSS Flexbox is easy. The only problem is it requires you to wrap the form in a parent container with a specified width, which is a bit of a pain. Thankfully, there’s a better solution that works in all browsers. You’ll need three elements: The actual form. A wrapper element (parent). An element for the actual content (child). We’ll use CSS Flexbox to center the web form to the browser center. Type and run the code below: .card__wrapper { height: 100%; display: flex; justify-content: center; align-items: center; } Browser Output In this section, we target the card__wrapper class, we set a height of 100%, a display of flex, justify-content of center, and align-items of center. This helps position the form to the center horizontally and vertically while styling CSS Forms. Styling the Form Element The HTML for a typical form consists of various input elements, each representing a different type of data. In CSS, you can style the input element in various ways to create distinction among them. Here we apply styling to the CSS form and add a specific width and height: .card__forms { display: flex; justify-content: center; width: 400px; height: 400px; background-color: rgb(1, 32, 32, 0.4); border-radius: 0.5rem; box-shadow: 3.5px 3.5px 4px 2px rgba(0, 0, 0, 0.3); border-top: 2px solid rgb(89, 250, 156); border-bottom: 2px solid rgb(89, 250, 156); } Browser Output We target the class of card__form, apply a display of flex, justify-content of center, width, and height of 400px across, to give it a defined size, background-color of rgb (1, 32, 32, 0.4). The last two integers of 0.4 are transparent values as they represent the opacity of the 0.4 value. We also added a border-radius of 0.5em, box-shadow, border-top, and border-bottom of 2px solid rgb(89, 250, 156). This creates the solid lime color you can see at the top and bottom of our CSS Form. Styling Form Logo Many websites use the form logo to style the input field and submit button in a form. The first reason is the form is consistent with the overall design. The second reason is it makes it easier to differentiate between a regular input field and a submit button since the color is used for the submit button. Here we apply styling to the logo on the form element: .site__logo { width: 40px; padding: 4px; margin: 2.0rem 5rem; text-align: center; border-radius: 50%; font-size: x-large; font-weight: bolder; font-family: 'Trebuchet MS', sans-serif; background-color: rgb(89, 250, 156); color: rgb(1, 32, 32); cursor: default; } Browser Output We targeted the site__logo class and we added a width of 40px, padding of 4px, margin of 2.0rem and 5rem for top and bottom, respectively (to add extra white space). We also apply text-align to center (to center the logo), border-radius of 50% (to make the logo round), font-size of x-large, font-weight of bolder, and font-family of “Trebuchet MS.” And a background-color of rgb (89, 250, 156), color of rgb (1, 32, 32) and cursor of default. Styling Site Caption The site caption is a little bit of text that appears at the top of every page on your website. This can be any text you want. It is typically used to identify who created the site and possibly provide legal information about the site’s content. By styling this text, we can make it stand out more or appear in multiple places on a page. Here we apply styling to the caption on the CSS Form: .sign__caption p { color: white; font-family: calibri; font-style: italic; text-transform: lowercase; margin-bottom: 1.5rem; } Browser Output We selected the sign__caption class and targeted the p tag inside it. We apply a text color of white, font-family of calibri, font-style of italic, text-transform to lowercase, and margin-bottom of 0.5 rem (to apply extra white space at the bottom). Styling the Input Tag The input tag comes with a few styles by default. It has the look of a text field, and it’s a good idea to use the default styling for the most part. The default styling provides enough contrast between elements so users can easily read and understand what they’re filling in. Here we apply styling to the input tag on the CSS form, where users can enter their information: .user_id input { width: 100%; display: block; outline: none; border: 0; padding: 1rem; border-radius: 20px; margin: 0.8rem 0; color: rgb(1, 32, 32); } .user_id input::placeholder{ color: rgb(1, 32, 32); } .user_id input:active { outline: 2px solid rgb(89, 250, 156); } Browser Output We apply the following values from the code sample above to the input tag nested inside the user id class: width: of 100% (so our input tag takes in a full size within the container). display: of a block (so the tag can be centered properly). outline: of none (to remove the outline around the input tag when we click on it). border: to 0px (to remove the gray border around the input tag). padding: of 1rem (to add more space within the tag input tag to give room for user’s input such as usernames and passwords). border-radius: of 20px (to give it a rounded curve at the edge). margin: of 0.8rem 0 (0.8rem added extra space at the top and bottom while the 0 means no space should be added to the left and right of the input tag). color: of rgb (1, 32, 32). For the placeholder, we added a text color of rgb (1, 32, 32), which is responsible for the “Username” and “Password” text. And for the active state, we added an outline color of 2px solid rgb (89, 250, 156). You will see the outline color when you click on the input field of the CSS form. Styling Forget Password It is necessary to style the password field and its labels in the forgot-password form. You may require use for this purpose a combination of standard CSS properties and some custom properties. Here, we apply styling to the label and a tag, providing two options for users who want their account to remain signed in and for users who forgot their password to recover it: .checkbox__wrapper label { color: white; font-family: calibri; text-transform: lowercase; } .checkbox__wrapper a { color: rgb(89, 250, 156); font-family: calibri; text-transform: lowercase; text-decoration: none; font-style: italic; } .checkbox__wrapper a:hover { color: rgb(255, 255, 255); font-family: calibri; text-transform: lowercase; text-decoration: none; font-style: normal; } Browser Output In this section, we targeted the label tag nested inside the .checkbox__wrapper class and applied the following styling to it. color: of white, a font-family of calibri. text-transform: of lowercase, while on the anchor tag. color: of rgb (89, 250, 156). text-decoration: to none (to remove the default blue line on the anchor tag). font-style: to italic to differentiate it from the label text. Since the anchor tag is a link that is meant to send a request, we decided to add a hover state, which is something to notify the user that this is a clickable link. On a hover state, we added a text color of rgb (255, 255, 255), and the font-style is set to normal to restore it. Style the Form Button The form button is the first thing a user will see on your website. A nice button can make a good impression, but a bad one can leave a user with a bad taste in their mouth before they even get to read any content. Here we apply styling to the button tag on CSS form. This button enables the user to sign into the website: .btn__wrapper button { width: 100%; border: none; padding: 1rem; border-radius: 20px; text-transform: uppercase; font-weight: bolder; margin: 0.8rem 0; color: rgb(1, 32, 32); } .btn__wrapper button:hover { background-color: rgb(89, 250, 156); color: white; transition: all 0.5s ease-in-out; cursor: pointer; } Browser Output In this section, we targeted the button tag nested in the btn__wrapper class, and we applied: width: of 100% to make it have a full width within the container. border: is set to none to remove the gray border around the button. padding: of 1rem to add space between the “SIGN IN” text and the button tag. border-radius: of 20px to apply a round corner style to the border. text-transform: is set to uppercase to capitalize the text. font-weight: is set to bolder to make text bold. margin: is set to 0.8rem at the top and bottom to give white space around the object, while 0 at the left and right. color: of rgb (1, 32, 32). On hover, we set the background-color to rgb (89, 250, 156), text color to white to create a kind of invert effect when we hover over it, a transition of all 0.5s ease-in-out, and a cursor of a pointer. To see these changes, move your mouse pointer to hover on the button. Styling the Signup Option The actual signup option is styled to look like a button. The design of the button is simple and recognizable so users will know what it does. The input size for the email address is a bit smaller than usual to ensure the user doesn’t have to scroll up and down every time they want to add an email address. Here we apply styling to the p and a tag, where we provide options for users who don’t have an account yet but want to sign up: .signup__option p { color: white; font-family: calibri; text-transform: lowercase; } .signup__option a { color: rgb(89, 250, 156); font-family: calibri; text-transform: lowercase; text-decoration: none; font-style: italic; } .signup__option a:hover { color: rgb(255, 255, 255); font-family: calibri; text-transform: lowercase; text-decoration: none; font-style: normal; } Browser Output From the browser output, you will notice that the “stay signed in / forgot password” and “don’t have an account yet? / sign up!” looks the same. Well, you guessed it right! We have to copy the CSS styles for the label tag of the checkbox__wrapper class and paste it on .signup__option a and then copy the styles on forget password and paste it on the sign up class. Now we should have the same effect. Here is the link to the finished project on styling CSS forms. Summary You have learned how to style forms using CSS. You also learned how to center items using Flexbox, using transition on buttons, apply background images, and how to cross text your website or web app using LambdaTest. Alright! We’ve come to the end of this tutorial. Thanks for taking your time to read this article to completion. Feel free to ask questions. I’ll gladly reply.
Javin Paul
Lead Developer,
infotech
Reza Rahman
Principal Program Manager, Java on Azure,
Microsoft
Kai Wähner
Technology Evangelist,
Confluent
Alvin Lee
Founder,
Out of the Box Development, LLC