r/graphic_design - How much should I charge as a beginner designer?
Strategy

How much should I charge as a beginner designer? : graphic_d…


I’ve trawled through this sub and found a lot of useful info on rates but am unsure about the quality of my work and pricing. I’m a 2nd year graphic design student who’s been approached by a company about making an instagram post. It’s only one post & my first commission.

They like my style (I have put some examples of my posters here), I started the poster everyday challenge this year and am relatively new to this so I feel as though I shouldn’t charge any more than £40 (being the higher end of the scale). Would appreciate some opinions on this thank you so much. Sorry if I’ve broken any rules.

r/graphic_design - How much should I charge as a beginner designer?



Source link

r/webdev - Aligning elements in navigation bar
Strategy

Aligning elements in navigation bar : webdev


I’m struggling to align a test image and a navigation toggle bar within my navigation menu. I’ve tried changing various properties of my HTML and CSS to try and align these two elements along with the other links that I have. The test image floats up and to the left of my links but I want it to be in a straight line with the links. The navigation toggle bar when in mobile view floats to the right like I want it to but it doesn’t space itself from the edges of the navigation menu.

The issue with the navigation toggle bar I think is due in part to my margins but I’m not entirely sure because when I changed properties of the test image it changes the behavior of the navigation toggle bar causing weird behavior. I tried changing the position and margins of the test image but can’t get it lined up properly. I’m not sure what I’m doing wrong or if I’m missing code to facilitate these changes.

Screenshots:

r/webdev - Aligning elements in navigation bar

In this image you can see how the current logo rests and is not in line with the links how I would like.

r/webdev - Aligning elements in navigation bar

This is the navigation toggle bar that isn’t properly centered in the navigation bar when the website switches to mobile view. In desktop mode the navigation toggle bar should disappear, which it does.

Here are all files I feel are relevant to this issue which can also be found on my github , some code was removed to make the files smaller for this post.

index.html

<!DOCTYPE html>
<html lang="en-US">
	<head>
		<meta charset="UTF-8">
		<meta name="description" content="Webpage for Projects">
		<meta name="author" content="Joseph Fitzgerald">
		<meta name="viewport" content="width=device-width, initial-scale=1.0"> 
		<link rel="stylesheet" href="CSS/index.css">
		<link rel="stylesheet" href="CSS/title.css">
		<link rel="stylesheet" href="CSS/footer.css">
		<link rel="stylesheet" href="CSS/navigation.css">
		<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
	</head>

	<body>
		<div class="top-container">
                /*Code removed*/
		</div>

		<nav class="fill-navbar" id="mynavBar">
			<img src="../Photos/test_logo2.png" alt="Logo" width="40px" height="40px">
			<span class="navbar-toggle" id="js-navbar-toggle">
				<i class="fa fa-bars"></i>
			</span>
			<ul class="main-nav" id="js-menu">
				<li><a class="active" href="index.html">Home</a></li>
      			<li><a href="About.html">About</a></li>
      			<li><a href="Projects.html">Projects</a></li>
			    <li><a href="Resume.html">Resume</a></li>
			    <li><a href="Contact.html">Contact</a></li>
 			</ul>
  		</nav>

		<div class="content">
			<p>Content</p>
			<article class="testArticle">
                            /*Code removed*/
			</article>
		</div>

		<footer class="flex-footer">
                    /*Code removed*/
		</footer>

		<script type="text/javascript" src="JAVASCRIPT/stickyNavScript.js"></script>
		<script type="text/javascript" src="JAVASCRIPT/navbartoggle.js"></script>

	</body>
</html>

index.css

html, body {
	height: 100%;
}

body {
	margin: 0;
  	font: 16px Sans-Serif;
	display: flex;
	flex-direction: column;
}

.top-container {
	background: #24305E;
	background: url("../Photos/5.jpg") no-repeat center;
	text-align: center;
	min-height: 100%;
}

.top-container > p {
	color: white;
}

.sticky{
	position: fixed;
	top: 0;
	/*width: 100%;*/
	left: 0;
	right: 0;
}

.sticky + .content {
	/*padding-top: 100px;*/
	padding-top: 60px;
}

.content {
	flex: 1 0 auto; /* Prevent Chrome, Opera, and Safari from letting these items shrink to smaller than their content's default minimum size. */
	padding: 20px;
	background-color: black;
}

.testArticle {
	color: white;
	background-color: black;
	padding: 4px;
	box-shadow: 0px 0px 8px 8px #13c6e4;
    -webkit-columns: 2 200px;
       -moz-columns: 2 200px;
            columns: 2 200px;
    -webkit-column-gap: 4em;
       -moz-column-gap: 4em;
            column-gap: 4em;
    -webkit-column-rule: 1px dotted #ddd;
       -moz-column-rule: 1px dotted #ddd;
            column-rule: 1px dotted #ddd;
}

navigation.css

/* NAVIGATION */
nav {
	width: 100%;
	/*Add a fixed height that is changed when the window is resized*/
	margin: 0 auto;
	/*Navigation color*/
	background: #040404; 
	padding: 2px 0; 
	border-bottom: 2px solid #ce1c69;
	position: relative;
}

nav ul {
	list-style: none;
	text-align: left;
}

nav ul li {
	display: inline-block; /*Changes how the buttons are stacked*/
}

nav ul li a {
	display: block; 
	padding: 4px; /*This is the padding around all these elements*/
	text-decoration: none;
	color: white; /*Changes button text color*/
	font-weight: 900;
	text-transform: uppercase;
	margin: 0 10px;
}

nav ul li a, nav ul li a:after, nav ul li a:before {
	transition: all .5s;
}

nav ul li a:hover {
	color: #555; /*This changes the color of the text when you hover over a button*/
}

nav ul li a.active{
	background: #ce1c69;
	border-radius: 20px;
}

/* stroke */
nav.stroke ul li a, nav.fill-navbar ul li a {
	position: relative;
}

nav.stroke ul li a:after, nav.fill-navbar ul li a:after {
	position: absolute;
	bottom: 0;
	left: 0;
	right: 0;
	margin: auto;
	width: 0%;
	content: '.'; 
	color: transparent;  
	background: #13c6e4; /*The little line that goes under the text first is this color before the button fills up*/
	height: 1px;
}

nav.stroke ul li a:hover:after {
	width: 100%;
}

nav.fill-navbar ul li a {
	transition: all 2s;
}

nav.fill-navbar ul li a:after {
	text-align: left;
	content: '.';
	margin: 0;
	opacity: 0;
}

nav.fill-navbar ul li a:hover {
	color: black; /*changes button text color on hover and fill*/
	z-index: 1;
}

nav.fill-navbar ul li a:hover:after {
	z-index: -10; /*Sets the fill animation to the background not the foreground*/
	animation: fill 1s forwards;
	-webkit-animation: fill 1s forwards;
	-moz-animation: fill 1s forwards;
	opacity: 1;
}

/* Keyframes */
@-webkit-keyframes fill {
	0% {
		width: 0%;
		height: 1px; /*THIS CHANGES THE HEIGHT OF THE STROKE AT THE BEGINNING OF THE ANIMATION */
	}
	50% {
		width: 100%;
		height: 1px; /*THIS CHANGES THE HEIGHT OF THE STROKE MID WAY THROUGH*/
	}
	100% {
		width: 100%;
		height: 100%;
		background: #13c6e4; /*Changes fill color*/
		border-radius: 20px;
	}
}

.logo{
	display: inline-block;
	background-color: white;
}

/*Hide the toggle bar while the screen is larger than 800px*/
.toggle-navbar{
	display: none;
}


@media only screen and (max-width: 800px) {
	.fill-navbar {
	    font-size: 18px;
	    background-color: #040404; 
	    padding-bottom: 10px;
	}

	.main-nav {
	    list-style-type: none;
	    display: none;
	}

	.main-nav li {
	    text-align: center;
	    margin: 10px auto;
	}

	.logo {
	    display: inline-block;
	    font-size: 22px;
	    margin-top: 10px;
	    margin-left: 20px;
	    background-color: white;
	}

	.navbar-toggle {
	    position: absolute;
	    top: 10px;
	    right: 20px;
	    cursor: pointer;
	    color: rgba(255, 255, 255, 0.8);
	    font-size: 24px;
	}

	/*This displays menu on mobile as a column*/
	ul#js-menu.main-nav.active{
		display: flex;
		flex-direction: column;
	}
}

stickNavScript.js

const nav = document.querySelector('#mynavBar')
const firstScreen = document.querySelector('.top-container')
document.addEventListener('scroll', function(e) {
  let scrollCount = self.pageYOffset || (document.documentElement && document.documentElement.scrollTop) || (document.body && document.body.scrollTop);

  if (scrollCount > firstScreen.clientHeight) {
    nav.classList.add('sticky')
  } else {
    nav.classList.remove('sticky')    
  }
}) 

navbartoggle.js

let mainNav = document.getElementById('js-menu');
let navBarToggle = document.getElementById('js-navbar-toggle');

navBarToggle.addEventListener('click', function () {
  mainNav.classList.toggle('active');
});

To see a live demo of all this you can visit the website and inspect element to change the view from desktop to mobile to see the navigation bar change. Note I haven’t added the test logo image to the other pages so you wont see it there. Any help or tips on this issue would be greatly appreciated!

Also if more information is needed please message me, thank you!



Source link

Post image
Strategy

I created Deskreen. This is a desktop app that makes any dev…


Post image

Deskreen Logo

Meet Deskreenan open source app that turns any device with a web browser into a secondary screen for your computer. Built with web technologies and ElectronJS so it is cross-platform. It supports Windows, MacOS and Linux.

Deskreen website: https://deskreen.com

Post image

Demonstrating Deskreen working with multiple devices at the same time.

Quick Demo Video On Youtube — Tablet as Second Screen for a laptop | Using Deskreen

Alternative video link can be viewed here:

Quick Demo Video — Tablet as Second Screen for a laptop | Using Deskreen

Features:

  • works with WiFi or LAN

  • use any device with web browser as second screen for your computer (using Display Dummy Plug)

  • use any device web browser to mirror your computer’s screen

  • use any device web browser to view a single application window from your computer’s screen

  • supports multiple screen sharing sessions to as many devices as you want

  • supports changing picture quality while sharing a screen.

  • Picture auto quality change supported. (for performance boost while watching youtube video for example)

  • End-to-end encryption

  • dark mode UI support 😉

  • available for Win / Mac / Linux

It all started with me wanting to use my iPad as a second screen for my Macbook. But I found that it is already outdated to use a MacOS built in feature called ‘Sidecar’ and I have to buy a new iPad, which I did not want to do. I also have a Windows PC and sometimes I needed to use my iPad as second screen for it as well. I tried to look for FREE solutions on internet, but I could not find anything that would fit my expectations. Besides, all methods using free software for screen sharing I found, were different for Windows, Mac and Linux. I got very confused about it. Then I got an idea of creating Deskreen. I decided to make it free and open-source to help people to solve this problem. Deskreen works the same for Windows, MacOS and Linux.

People nowadays are buying new devices very often and may have an old tablet, phone or laptop that they stopped using. If your old tablet, phone or laptop is still able to run a browser, Deskreen can help you to bring a new life to your old digital buddy, and you can start using it as a second monitor for your laptop.

Note: app is not Code-Signed yet, code signing is pricy. Any donations are highly encouraged. Donate on Patreon

Links:

Deskreen on Github

Deskreen on Patreon

Deskreen creator’s LinkedIn

High Level Architecture Design of Deskreen

Thank you all for your attention,

Paul



Source link

The first rectangle contains an inner element that overflows both the top and bottom edges with the text "Possible" below it. The second rectangle clips the inner element on both sides, with "Also possible" below it. The third rectangle clips the inner element on the bottom, but shows it overflowing at the top, with the text "...Not possible" below it.
Strategy

Re-Creating the Porky Pig Animation from Looney Tunes in CSS


You know, Porky Pig coming out of those red rings announcing the end of a Looney Tunes cartoon. We’ll get there, but first we need to cover some CSS concepts.


Everything in CSS is a box, or rectangle. Rectangles stack, and can be displayed on top of, or below, other rectangles. Rectangles can contain other rectangles and you can style them such that the inner rectangle is visible outside the outer rectangle (so they overflow) or that they’re clipped by the outer rectangle (using overflow: hidden). So far, so good.

What if you want a rectangle to be visible outside its surrounding rectangle, but only on one side. That’s not possible, right?

The first rectangle contains an inner element that overflows both the top and bottom edges with the text "Possible" below it. The second rectangle clips the inner element on both sides, with "Also possible" below it. The third rectangle clips the inner element on the bottom, but shows it overflowing at the top, with the text "...Not possible" below it.

Perhaps, when you look at the image above, the wheels start turning: What if I copy the inner rectangle and clip half of it and then position it exactly?. But when it comes down to it, you can’t choose to have an element overflow at the top but clip at the bottom.

Or can you?

3D transforms

Using 3D transforms you can rotate, transform, and translate elements in 3D space. Here’s a group of practical examples I gathered showcasing some possibilities.

For 3D transforms to do their thing, you need two CSS properties:

  • perspective, using a value in pixels, to determine how pronounced the 3D effect is
  • transform-style: preserve-3d, to tell the browser to keep elements positioned in 3D space.

Even with the good support that 3D transforms have, you don’t see 3D transforms ‘in the wild’ all that much, sadly. Websites are still a “2D” thing, a flat page that scrolls. But as I started playing around with 3D transforms and scouting examples, I found one that was by far the most interesting as far as 3D transforms go:

Three planes floating above each other in 3D space

The image clearly shows three planes but this effect is achieved using a single <div>. The two other planes are the ::before and ::after pseudo-elements that are moved up and down respectively, using translate(), to stack on top of each other in 3D space. What is noticeable here is how the ::after element, that normally would be positioned on top of an element, is behind that element. The creator was able to achieve this by adding transform: translateZ(-1px);.

Even though this was one of many 3D transforms I had seen at this point, it was the first one that made me realize that I was actually positioning elements in 3D space. And if I can do that, I can also make elements intersect:

Two planes intersecting each other in 3D space

I couldn’t think of how this sort of thing would be useful, but then I saw the Porky Pig cartoon animation. He emerges from behind the bottom frame, but his face overlaps and stacks on top of the top edge of the same frame — the exact same sort of clipping situation we saw earlier. That’s when my wheels started turning. Could I replicate that effect using just CSS? And for extra credit, could I replicate it using a single <div>?

I started playing around and relatively quickly had this to show for it:

An orange rectangle that intersects through a blue frame. At the top of the image it's above the frame and at the bottom of the image it's below the blue frame.

Here we have a single <div> with its ::before and an ::after pseudo-elements. The div itself is transparent, the ::before has a blue border and the ::after has been rotated along the x-axis. Because the div has perspective, everything is positioned in 3D and, because of that, the ::after pseudo-element is above the border at the top edge of the frame and behind the border at the bottom edge of the frame.

Here’s that in code:

div {
  transform: perspective(3000px);
  transform-style: preserve-3d;
  position: relative;
  width: 200px;
  height: 200px;
}

div::before {
  content: "";
  width: 100%;
  height: 100%;
  border:10px solid darkblue;
}

div::after {
  content: "";
  position: absolute;
  background: orangered;
  width: 80%;
  height: 150%;
  display: block;
  left: 10%;
  bottom: -25%;
  transform: rotateX(-10deg);
}

With perspective, we can determine how far a viewer is from “z=0” which we can consider to be the “horizon” of our CSS 3D space. The larger the perspective, the less pronounced the 3D effect, and vice versa. For most 3D scenes, a perspective value between 500 and 1,000 pixels works best, though you can play around with it to get the exact effect you want. You can compare this with perspective drawing: If you draw two horizon points close together, you get a very strong perspective; but if they’re far apart, then things appear flatter.

From rectangles to cartoons

Rectangles are fun, but what I really wanted to build was something like this:

A film cell of Porky Pig coming out of a circle with the text "That's all folks."

I couldn‘t find or create a nicely cut-out version of Porky Pig from that image, but the Wikipedia page contains a nice alternative, so we’ll use that.

First, we need to split the image up into three parts:

  • <div>: the blue background behind Porky
  • ::after: all the red circles that form a sort of tunnel
  • ::before: Porky Pig himself in all his glory, set as a background image

We’ll start with the <div>. That will be the background as well as the base for the rest of the elements. It’ll also contain the perspective and transform-style properties I called out earlier, along with some sizes and the background color:

div {
  transform: perspective(3000px);
  transform-style:preserve-3d;
  position: relative;
  width: 200px;
  height: 200px;
  background: #4992AD;
}

Alright, next up, we‘ll move to the red circles. The element itself has to be transparent because that’s the opening where Porky emerges. So how shall we go about it? We can use a border just like the example earlier in this article, but we only have one border and that can have a solid color. We need a bunch of circles that can accept gradients. We can use box-shadow instead, chaining multiple shadows in the property values. This gets us all of the circles we need, and by using a blur radius value of 0 with a large spread radius, we can create the appearance of multiple “borders.”

box-shadow: <x-offset> <y-offset> <blur-radius> <spread-radius> <color>;

We‘ll use a border-radius that‘s as large as the <div> itself, making the ::before a circle. Then we’ll add the shadows. When we add a few red circles with a large spread and add blurry white, we get an effect that looks very similar to the Porky’s tunnel.

box-shadow: 0 0 20px   0px #fff, 0 0 0  30px #CF331F,
            0 0 20px  30px #fff, 0 0 0  60px #CF331F,
            0 0 20px  60px #fff, 0 0 0  90px #CF331F,
            0 0 20px  90px #fff, 0 0 0 120px #CF331F,
            0 0 20px 120px #fff, 0 0 0 150px #CF331F;

Here, we’re adding five circles, where each is 30px wide. Each circle has a solid red background. And, by using white shadows with a blur radius of 20px on top of that, we create the gradient effect.

The background and circles in pure CSS without Porky

With the background and the circles sorted, we’re now going to add Porky. Let’s start with adding him at the spot we want him to end up, for now above the circles.

div::before {
  position: absolute;
  content: "";
  width: 80%;
  height: 150%;
  display: block;
  left: 10%;
  bottom: -12%;
  background: url("Porky_Pig.svg") no-repeat center/contain;
}

You might have noticed that slash in “center/contain” for the background. That’s the syntax to set both the position (center) and size (contain) in the background shorthand CSS property. The slash syntax is also used in the font shorthand CSS property where it’s used to set the font-size and line-height like so: <font-size>/<line-height>.

The slash syntax will be used more in future versions of CSS. For example, the updated rgb() and hsl() color syntax can take a slash followed by a number to indicate the opacity, like so: rgb(0 0 0 / 0.5). That way, there’s not need to switch between rgb() and rgba(). This already works in all browsers, except Internet Explorer 11.

Porky Pig positioned above the circles

Both the size and positioning here is a little arbitrary, so play around with that as you see fit. We’re a lot closer to what we want, but now need to get it so the bottom portion of Porky is behind the red circles and his top half remains visible.

The trick

We need to transpose both the circles as well as Porky in 3D space. If we want to rotate Porky, there are a few requirements we need to meet:

  • He should not clip through the background.
  • We should not rotate him so far that the image distorts.
  • His lower body should be below the red circles and his upper body should be above them.

To make sure Porky doesn‘t clip through the background, we first move the circles in the Z direction to make them appear closer to the viewer. Because preserve-3d is applied it means they also zoom in a bit, but if we only move them a smidge, the zoom effect isn’t noticeable and we end up with enough space between the background and the circles:

transform: translateZ(20px);

Now Porky. We’re going to rotate him around the X-axis, causing his upper body to move closer to us, and the lower part to move away. We can do this with:

transform: rotateX(-10deg);

This looks pretty bad at first. Porky is partially hidden behind the blue background, and he’s also clipping through the circles in a weird way.

Porky Pig partially clipped by the background and the circles

We can solve this by moving Porky “closer” to us (like we did with the circles) using translateZ(), but a better solution is to change the position of our rotation point. Right now it happens from the center of the image, causing the lower half of the image to rotate away from us.

If we move the starting point of the rotation toward the bottom of the image, or even a little bit below that, then the entirety of the image rotates toward us. And because we already moved the circles closer to us, everything ends up looking as it should:

transform: rotateX(-10deg);
transform-origin: center 120%;
Porky Pig emerges from the circle, with his legs behind the circles but his head above them.

To get an idea of how everything works in 3D, click “show debug” in the following Pen:

Animation

If we keep things as they are — a static image — then we wouldn’t have needed to go through all this trouble. But when we animate things, we can reveal the layering and enhance the effect.

Here‘s the animation I’m going for: Porky starts out small at the bottom behind the circles, then zooms in, emerging from the blue background over the red circles. He stays there for a bit, then moves back out again.

We’ll use transform for the animation to get the best performance. And because we’re doing that, we need to make sure we keep the rotateX in there as well.

@keyframes zoom {
  0% {
    transform: rotateX(-10deg) scale(0.66);
  }
  40% {
    transform: rotateX(-10deg) scale(1);
  }
  60% {
    transform: rotateX(-10deg) scale(1);
  }
  100% {
    transform: rotateX(-10deg) scale(0.66);
  }
}

Soon, we’ll be able to directly set different transforms, as browsers have started implementing them as individual CSS properties. That means that repeating that rotateX(-10deg) will eventually be unnecessary; but for now, we have a little bit of duplication.

We zoom in and out using the scale() function and, because we’ve already set a transform-origin, scaling happens from the center-bottom of the image, which is precisely the effect we want! We’re animating the scale up to 60% of Porky’s actual size, we have the little break at the largest point, where he fully pops out of the circle frame.

The animation goes on the ::before pseudo-element. To make the animation look a little more natural, we’re using an ease-in-out timing function, which slows down the animation at the start and end.

div::before {
  animation-name: zoom;
  animation-duration: 4s;
  animation-iteration-count: infinite;
  animation-fill-mode:forwards;
  animation-timing-function: ease-in-out;
}

What about reduced motion?

Glad you asked! For people who are sensitive to animations and prefer reduced or no motion, we can reach for the prefers-reduced-motion media query. Instead of removing the full animation, we’ll target those who prefer reduced motion and use a more subtle fade effect rather than the full-blown animation.

@media (prefers-reduced-motion: reduce) {
   @keyframes zoom {
    0% {
      opacity:0;
    }
    100% {
      opacity: 1;
    }
  }

  div::before {
    animation-iteration-count: 1;
  }
}

By overwriting the @keyframes inside a media query, the browser will automatically pick it up. This way, we still accentuate the effect of Porky emerging from the circles. And by setting animation-iteration-count to 1, we still let people see the effect, but then stop to prevent continued motion.

Finishing touches

Two more things we can do to make this a bit more fun:

  • We can create more depth in the image by adding a shadow behind Porky that grows as he emerges and appears to zoom in closer to the view.
  • We can turn Porky as he moves, to embellish the pop-out effect even further.

That second part we can implement using rotateZ() in the same animation. Easy breezy.

But the first part requires an additional trick. Because we use an image for Porky, we can’t use box-shadow because that creates a shadow around the box of the ::before pseudo-element instead of around the shape of Porky Pig.

That’s where filter: drop-shadow() comes to the rescue. It looks at the opaque parts of the element and adds a shadow to that instead of around the box.

@keyframes zoom {
  0% {
    transform: rotateX(-10deg) scale(0.66);
    filter: drop-shadow(-5px 5px 5px rgba(0,0,0,0));
  }
  40% {
    transform: rotateZ(-10deg) rotateX(-10deg) scale(1);
    filter: drop-shadow(-10px 10px 10px rgba(0,0,0,0.5));
  }

  60% {
    transform: rotateZ(-10deg) rotateX(-10deg) scale(1);
    filter: drop-shadow(-10px 10px 10px rgba(0,0,0,0.5));
  }

  100% {
    transform: rotateX(-10deg) scale(0.66);
    filter: drop-shadow(-5px 5px 5px rgba(0,0,0,0));
  }
}

And that‘s how I re-created the Looney Tunes animation of Porky Pig. All I can say now is, “That’s all Folks!”



Source link

The Messenger Component (Symfony) - DZone Web Dev
Strategy

The Messenger Component (Symfony) – DZone Web Dev


Back in March 2018, the pleasing news that the family of Symfony components was replenished with a useful Messenger tool spread quickly among developers. According to the creators, this Symfony tool had to take on the task of sending/receiving messages to/from other applications, as well as queue management.

Naturally, the appearance of an interesting tool causes a desire to implement it quickly in projects. However, few people can afford it. Therefore, we did not risk our time, as well as stability of our customers’ applications, and postponed the question.

And now, 2020 has arrived, and every time I look through the Changelog of the new Symfony releases, I run into the Messenger edits. It’s obvious that the work has been in full swing for almost two years, the component seems to be more stable already, which means it’s time to take a closer look at it.

I don’t like to copy examples from documentation, so I decided to focus on conceptual things myself, and to study the structure of the Messenger, its basic abstractions, and the tasks assigned to them.

The Difficulty of Perception

I’ll start with a small lyrical digression and touch on the topic of the complexity of information perception.

The complexity of studying a new topic to a great extent depends on how the author presents the material (under the term material I mean: documentation, articles, screencast, etc.). You‘ve have probably heard of, or possibly met, the people who are real professionals in their field, but who are absolutely incapable of expressing themselves in a simple way, and sometimes their attempts to do this only make the situation worse.

The knowledge transfer is not a completely formalized process, that is, there is no special approach in which every student will understand the material quickly and correctly. Therefore, everyone does it the way they can.

I decided to write about it because the first thing I came across when I started to study Messenger was the block diagram presented below, and despite the fact that schemes should simplify the perception, it had the opposite effect on me.

Source: https://symfony.com/doc/current/components/messenger.html

For you not to spend much time, I would like to make some thesis recommendations on reading this scheme:

  • Your message, and it can be any object, turns into an additional wrapper called Envelope. You can see this by looking at the implementation of the dispatch method of the MessageBusclass.
  • Inside the Bus, Envelope passes through a chain of Middlewares with the help of which additional logic can be used (it’s not reflected in the diagram).
  • Stamps: This is the metadata that allows you to actually manage your message inside Middlewares (it’s not reflected in the diagram). The principle is extremely simple if Envelope is sent with some kind of Stamp, knowing it we can perform additional logic;
  • Having passed the Envelope through all Middlewares, the Bus uses the Transport you specified and finally sends a message;
  • The diagram shows that the Receiver, Bus and Sender have the same color. In my opinion, this is not exactly correct. The Receiver and Sender are Transport.

You can make it sure by studying the structure of the Message component a little.

Thus, under the phrase “the Bus uses Transport,” it is assumed that the Sender of the specified Transport will be activated for your message. A similar conclusion applies to the Receiver; the circles on the diagram mark specifically the 3rd part systems such as RabbitMQ, Doctrine, Redis, etc.

I would be glad if these notes help you to gain insight into the scheme quickly. I succeeded in it only after I had studied the codebase and examples from the documentation.

Message Bus

It’s a basic abstraction, the tasks of which include control over the process of sending a message and its transfer to the handler. Despite the fact that the tasks assigned to the Bus are the key ones, it is a fairly simple class with one dispatch method. The thing is that Bus does it in a very elegant way.

As you can see from the code, the Bus performs only two key functions: it wraps the message into the Envelope (more details about this abstraction later) and passes the message iteratively through Middlewares.

Middlewares are the very building blocks that implement Messenger’s basic logic. It is worth knowing that Middlewares are fulfilled according to the order in which they are registered in the container.

Of course, you can also implement any business logic in your Middlewares, but keep in mind that SendMessageMiddleware and HandleMessageMiddleware are always executed last … which is generally logical 🙂

The list available can be obtained by running the following command:

At the time of article writing, it’s:

Middleware, Envelope, and Stamps

An object, as an option for transmitting a message, is chosen for a reason; it is a great way to transfer context to the other parts of the system.

What does context mean in this case? This is the set of data that is needed to process a message. For example, we need to send a greeting letter after a new user is registered. We can create a UserRegisteredMessage message class and store the UUID in it as a context. The Handler will find this UUID of the user in the database and send him a letter to the mailing address.

It is easy to understand and clear from EventDispatcher. What are the reasons for the appearance of the Envelope and Stamp abstractions then?

I have already mentioned that Bus passes a message through the intermediate logic, the so-called Middlewares. We can manage our message within each Middleware.

Now the question arises if I want Middleware 1 to do nothing with the message, and some logic to be fulfilled in Middleware 2, how can I notify Middleware 2 about it? (see the diagram below).

An option is to check the instance of the transmitted message in Middleware 2.

This is a good solution, but then Middleware 2 will be tightly associated with a specific message. I do not exclude that such cases can also be, but what if we are dealing with a universal Middleware that must process different messages?

Here we come to the idea of metadata, that is, some kind of auxiliary data set that should be sent along with the message. Stamps does it This is a marker that carries its own context.

And this is the root cause of the Stamps. As for Envelope, you need to answer the following question: how correctly is it to transfer metadata along with the message context? I mean, save Stamps directly in the message object.

The answer is the following: it will be a very gross violation, because the message context comes out of the business requirements while the metadata out of the implementation.

This leads to the second idea that contexts need to be transferred as separate objects, and to control them, you need an auxiliary abstraction, a certain control object. This function was assigned just to Envelope. He acts as a wrapper for our post and adds the ability to bind Stamps to a message.

Let’s consolidate our understanding of the concept with a simple example. Suppose you want to validate a message before sending it to a handler. This problem can be solved with the help of ValidationMiddleware available from the box. Pay attention to the 39th line, the validator will work if the ValidationStamp was attached to Envelope

To do this, during dispatch, we will pass a ValidationStamp object with the name of the validation group. And then in case of an error, a ValidationFailedException will be dropped, which can be handled by the caller.

Transport, Sender, and Receiver

For a better understanding of what the Transport is, it’s better to think of it as of some kind of repository for working with which two more abstractions are needed, the Sender, which implements sending a message to the repository, and the Receiver, which takes this message from the repository and sends it to the handler.

Out of the box, we have three asynchronous Transports: AmqpExt, RedisExt and Doctrine, as well as two synchronous ones: In Memory and Sync. Moreover, the implementation of the Receiver is not required for Sync since the Messages are immediately sent to Handler. In general, it does the same as EventDispatcher (well, you’ve got it, have you ;)).

Of course, you have the opportunity to create your own custom Transport. For this, the two TransportFactory and TransportInterface interfaces must be implemented.

The aspect of Transports can take one more full article, because there are a lot of questions, ranging from configuration and queue management to the worker and deployment operating. But since the purpose of the article is to describe the basic abstractions and their tasks; I will stick to a brief review of this topic.

Conclusion

The conclusion is clear: Messenger is a useful Symfony development tool and we will definitely use it in our company’s future projects.

In fact, we get an improved EventDispatcher with routing, Middlewares, the ability to control the message through Stamps, and also to use various Transport, including asynchronous.

Drawing such conclusions, I have, in fact, put Messenger on a par with EventDispatcher, but I want to emphasize that I am aware of the difference in the approaches these two components use.

EventDispatcher dispatches, and Listeners / Subscribers process. At the same time, the Messenger both sends and controls processing. So we can summarize that Messenger can do everything that EventDispatcher does and even more, but as to the EventDispatcher it’s wrong to say the same, since it is limited compared to the first tool.

You have the right to decide yourself what to use, but I would prefer Messenger as a more flexible alternative.

Now let’s see some statistics. At the time of writing the article, the packagist.org stated:

1.8 million installations and almost 500 stars.

As to the issues we have 41/190 (opened / closed) of which:

  • Bugs: 13/93
  • Performance: 2/5
  • Feature: 31/160

As you can see, the community is actively interested and works to improve stability of the component, as well as adds new features.

And finally, in the process of studying the materials available on the Internet, I came across a rather interesting article on the topic. I am not familiar with the author, but I am very impressed with the way the information presented, so I recommend you read it: https://vria.eu/delve_into_the_heart_of_the_symfony_messenger/

Well, and now have the colorful Cheat Sheet :): https://medium.com/@andreiabohner/symfony-4-4-messenger-cheat-sheet-5ca99cbba4a8

Thank you for reading up to the end. Good luck!



Source link

How to Completely Uninstall Xcode From Mac
Strategy

How to Completely Uninstall Xcode From Mac


Xcode is one of the best Integrated Development Environments (IDEs) for writing, testing, and deploying Apple apps. Creating applications for Mac and iOS devices is a lot easier with Xcode. Despite being a super app development tool with several benefits, Xcode has one huge downside: it’s a data hog.

The (latest version of the) app is about 11GB on the App Store. During usage, Xcode also creates a lot of temporary cache files that consume an insane amount of storage space. In the long run, these temp files may cause the app (and your Mac) to freeze or malfunction during usage.

Why and When Should You Uninstall Xcode?

Sometimes, the best way to fix the issues and prevent Xcode from filling up your hard drive is to uninstall the app and reinstall it from scratch. So when some features of Xcode consistently malfunction time and time again, you might want to completely remove the app from your Mac.

Say, for example, XCode fails to compile your app or install some vital components/simulators. Uninstalling the app might be the next best thing if all troubleshooting solutions prove abortive.

You may also need to uninstall Xcode if you’re selling off your Mac or gifting it tot someone who isn’t a developer.

How to Uninstall XCode From Your Mac

Before you proceed to uninstall Xcode, we recommend that you find where the app’s files and components are located on your Mac. That’ll give you an idea of where to look when you need to delete Xcode’s leftover files after uninstalling the app.

You can use the mdfind command in Terminal to locate all the files associated with the Xcode app. Here’s how to get it done.

1. Go to Finder > Applications > Utilities and double-click Terminal.

2. Type or paste the command below into the Terminal console and press Return on your keyboard.

mdfind -name "xcode"

3. Take note of the directories and file paths in the results.

You can run the command again after uninstalling Xcode to find any leftover file. Mind you, you shouldn’t delete all directories displayed in the results. Files and folders commonly associated with Xcode are listed below:

  1. /Applications/Xcode.app

  2. ~/Library/MobileDevice

  3. ~/Library/Developer

  4. /System/Library/Receipts/com.apple.pkg.XcodeSystemResources.plist

  5. /System/Library/Receipts/com.apple.pkg.XcodeExtensionSupport.plist

  6. /System/Library/Receipts/com.apple.pkg.XcodeSystemResources.bom

  7. /System/Library/Receipts/com.apple.pkg.XcodeExtensionSupport.bom

  8. ~/Library/Caches/com.apple.dt.Xcode

  9. /Library/Preferences/com.apple.dt.Xcode.plist

  10. ~/Library/Preferences/com.apple.dt.Xcode.plist

This list is by no means definitive. You may find extra Xcode files in directories not listed above on your Mac. That’s why you should use the mdfind command to locate the files before uninstalling Xcode.

When you uninstall Xcode from your Mac, a bunch of these files will be deleted. However, some files may still be lurking behind. Follow the steps below to uninstall Xcode and completely remove all its associated data—leftover files and components.

Step 1: Delete the Xcode App

The first step to uninstalling Xcode from your Mac (and deleting its residual files) is to move the app itself to the macOS Bin. Launch Finder and click Applications on the right sidebar. Right-click on the Xcode icon and select Move to Bin on the context menu.

That will immediately uninstall Xcode from your Mac. Now, proceed to remove its residual files.

Step 2: Delete Xcode’s Residual Files

The files of newer Xcode versions are usually consolidated in the ~/Library/Developer/ folder. You may also find support files in the ~/Library/Caches/ folder. If your Mac doesn’t delete these files/folders after uninstalling Xcode, you should.

To do so, launch Terminal (go to Finder > Applications > Utilities > Terminal) and paste the following command.

sudo rm -rf ~/Library/Developer/

Enter your Mac’s password and press Return. This command will remove Xcode’s leftover files in the Developer folder. An alternative route is to launch the Go to Folder windows (Shift + Command + G), paste ~/Library/ into the dialog box, and click Go.  

Right-click the Developer folder and select Move to Bin.

Execute the next command to delete other support files in the Library cache folder.

sudo rm -rf ~/Library/Caches/com.apple.dt.XcodePaste the command above and press Return. The folder will be deleted after entering your Mac’s password.

Proceed to empty your Mac’s Bin after uninstalling Xcode and deleting the residual files. You can also run the mdfind command in Terminal to confirm that the files have indeed been deleted.

If you find that some Xcode files are still resident on your Mac’s hard drive, you probably have an old version of the Xcode app. To delete the legacy files of legacy Xcode versions, launch Terminal and paste the command below into the console.

sudo /Developer/Library/uninstall-devtools --mode=allPress Return, enter your Mac’s password, and press Return again.

Files generated by Xcode and its components run into tens of gigabytes. This can take a toll on your Mac’s storage and performance, especially if you’re running out of available space. Follow the steps in this guide to completely remove all Xcode’s files from your Mac.



Source link