<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:series="http://unfoldingneurons.com/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Nettuts+</title> <link>http://net.tutsplus.com</link> <description>Web Development &amp; Design Tutorials</description> <lastBuildDate>Tue, 21 May 2013 15:17:17 +0000</lastBuildDate> <language /> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.5</generator> <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/nettuts" /><feedburner:info uri="nettuts" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><image><link>http://nettuts.com</link><url>http://envato.s3.amazonaws.com/rss_images/nettuts.jpg</url><title>NETTUTS</title></image><feedburner:emailServiceId>nettuts</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item><title>The Right Way to Retinafy Your Websites</title><link>http://feedproxy.google.com/~r/nettuts/~3/og52Nv0vAjs/</link> <comments>http://net.tutsplus.com/tutorials/html-css-techniques/the-right-way-to-retinafy-your-websites/#comments</comments> <pubDate>Tue, 21 May 2013 14:55:30 +0000</pubDate> <dc:creator>Allan Berger</dc:creator> <category><![CDATA[HTML & CSS]]></category> <category><![CDATA[retina]]></category> <guid isPermaLink="false">http://net.tutsplus.com/?p=31793</guid> <description>&lt;a
href='http://rss.buysellads.com/click.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31793&amp;c=1504794486' target='_blank'&gt;&lt;img
src='http://rss.buysellads.com/img.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31793&amp;c=1504794486' border='0' alt='' /&gt;&lt;/a&gt;&lt;p&gt; Making your website ready for Retina display doesn&amp;rsquo;t have to be a hassle. Whether you are building a new website or upgrading an existing one, this guide is designed to help you get the job done smoothly.&lt;/p&gt;&lt;p&gt;&lt;span
id="more-31793"&gt;&lt;/span&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Make it Retina First&lt;/h2&gt;&lt;p&gt; The easiest and most time-saving way to add Retina support is to create one image that is optimized for Retina devices, and serve it to non-Retina devices as well.&lt;/p&gt;&lt;p&gt; By now, every &lt;a
href="http://stackoverflow.com/questions/3382376/is-it-acceptable-to-leave-image-resizing-up-to-the-client-browser" target="_blank"&gt;modern browser&lt;/a&gt; uses bicubic resampling and does a great job with downsampling images. Here&amp;#8217;s a comparison of downsampling in Photoshop vs. Google Chrome, using an image from our &lt;a
href="http://www.growthengineering101.com" target="_blank"&gt;Growth Engineering 101&lt;/a&gt; website.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="Growth Engineering 101" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/growth-hacking-image-1.png" /&gt;&lt;/figure&gt;&lt;p&gt; There are two ways to let the browser downsample images for you: &lt;code&gt;img&lt;/code&gt; tags or CSS background images.&lt;/p&gt;&lt;p&gt; You can have &lt;code&gt;img&lt;/code&gt; tags serve the Retina-optimized image, and set the width and height attributes to half of the resolution of the actual image (e.g. &lt;em&gt;400&amp;#215;300&lt;/em&gt; if the image dimensions are &lt;em&gt;800&amp;#215;600&lt;/em&gt;).&lt;/p&gt;&lt;pre class="brush: xml; title: ; notranslate"&gt;
&amp;lt;img src=&amp;quot;http://www.example.com/Retina-image-800x600-2x.png&amp;quot; width=&amp;quot;400&amp;quot; height=&amp;quot;300&amp;quot;&amp;gt;
&lt;/pre&gt;&lt;p&gt; If you use images as CSS backgrounds, you may use the CSS3 &lt;code&gt;background-size&lt;/code&gt; property to downsample the image for non-Retina devices.&lt;/p&gt;&lt;pre class="brush: xml; title: ; notranslate"&gt;
&amp;lt;div class=&amp;quot;photo&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/pre&gt;&lt;pre class="brush: css; title: ; notranslate"&gt;
.photo {
    background-image: url(Retina-image-800x600-2x.png);
    background-size: 400px 300px;
    background-repeat: no-repeat;
    display: block;
    width: 400px;
    height: 300px;
}
&lt;/pre&gt;&lt;p&gt; In both cases, be sure to use even numbers in both dimensions to prevent displacement of pixels when the image is being downsampled by the browser.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;When Downsampling is Not Good Enough&lt;/h2&gt;&lt;p&gt; Usually, browser downsampling should work quite well. That said, there are some situations where downsampling in the browser might make images blurry.&lt;/p&gt;&lt;p&gt; Here we have a bunch of &lt;code&gt;32px&lt;/code&gt; social icons.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="32x32 px social icons" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/32pixel-icons-2.png" /&gt;&lt;/figure&gt;&lt;p&gt; And here is how they will appear, when downsampled to &lt;code&gt;16px&lt;/code&gt; by Photoshop&amp;rsquo;s as well as Google Chrome&amp;rsquo;s bicubic filter. It seems that we get better results from Photoshop in this case.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="16x16 px social icons - Transparent BG - Chrome vs Photoshop" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/16pixel-icons-3.png" /&gt;&lt;/figure&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="16x16 px social icons - White BG - Chrome vs Photoshop" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/16pixel-icons-4.png" /&gt;&lt;/figure&gt;&lt;p&gt; To get the best results for our users, we can create two versions of the same image: one for Retina devices, and another one that has been downsampled by Photoshop for non-Retina devices.&lt;/p&gt;&lt;p&gt; Now, you can use CSS media queries to serve Retina or non-Retina images, dependent upon the pixel density of the device.&lt;/p&gt;&lt;pre class="brush: css; title: ; notranslate"&gt;
/* CSS for devices with normal screens */
.icons {
    background-image: url(icon-sprite.png);
    background-repeat: no-repeat;
}
&lt;/pre&gt;&lt;pre class="brush: css; title: ; notranslate"&gt;/* CSS for high-resolution devices */
@media only screen and (-Webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
    .icons {
        background-image: url(icon-sprite-2x.png);
        background-size: 200px 100px;
        background-repeat: no-repeat;
    }
}
&lt;/pre&gt;&lt;p&gt; If you use a background color for small icons, on the other hand, downsampling by the browser works rather well. Here is the same downsampling example with a white background.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="16x16 px social icons - Zoom 200%" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/16pixel-zoom-5.png" /&gt;&lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;Polishing Your Downsampled Images&lt;/h2&gt;&lt;p&gt; If you&amp;rsquo;re still not satisfied with the results from Photoshop&amp;rsquo;s downsampling, you can go the extra mile and &lt;em&gt;hand-optimize&lt;/em&gt; the non-Retina version to get super crisp results.&lt;/p&gt;&lt;p&gt; Below are some examples of images from the &lt;a
href="https://www.blossom.io" target="_blank"&gt;Blossom&lt;/a&gt; product website that I &lt;em&gt;hand-optimized&lt;/em&gt; for those who are still on non-Retina devices.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Borders and Strokes&lt;/h2&gt;&lt;p&gt; Here&amp;#8217;s an example of downsampling issues with hairlines, where I re-draw the lines of the downsampled image.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="Borders and Strokes - Teaser Image" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/product-teaser-preview-6.png" /&gt;&lt;/figure&gt;&lt;p&gt; View the Retina Version of this Image on &lt;a
href="http://dribbble.com/shots/1047231-Blossom-Retina-Ready-Landing-Page/attachments/127611" target="_blank"&gt;Dribbble&lt;/a&gt;.&lt;/br&gt;&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="Borders and Strokes - Photoshop vs Chrome" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/product-teaser-optim-7.png" /&gt;&lt;/figure&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="Borders and Strokes - Photoshop vs Hand" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/product-teaser-optim-8.png" /&gt;&lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;Text&lt;/h2&gt;&lt;p&gt; Next, we come to an example of downsampling issues with text. In this case, I manually re-wrote the text &amp;ldquo;Feature Pipeline&amp;rdquo; to make the result as crisp as possible.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="Text - Original" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/text-retina-9.png" /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;&lt;h5&gt;Retina Version&lt;/h5&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="Text - Photoshop vs Hand" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/text-comparison-10.png" /&gt;&lt;/figure&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="Text - Photoshop vs Chrome" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/text-comparison-11.png" /&gt;&lt;/figure&gt;&lt;p&gt; When details, crisp fonts, and clean hairlines are important, you might want to go the extra mile.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Try to Avoid Images&lt;/h2&gt;&lt;p&gt; The main disadvantages of rasterized images are their considerable file size and that they don&amp;rsquo;t scale well to different sizes without affecting the image quality. Great alternatives to rasterized graphics are CSS, Scalable Vector Graphics (SVG), and Icon Fonts.&lt;/p&gt;&lt;p&gt; If you have any chance to build the graphical elements for your website in CSS, go for it. It can be used to add gradients, borders, rounded corners, shadows, arrows, rotate elements and much more.&lt;/p&gt;&lt;p&gt; Here are a few examples of interaction elements in Blossom that are implemented in CSS. The subtle gradient is powered by CSS gradients, and the custom font in use on this button is Kievit, served via &lt;a
href="https://typekit.com/"&gt;Typekit&lt;/a&gt;. No images.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="CSS Solution - Button" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/css-button-12.png" /&gt;&lt;/figure&gt;&lt;p&gt; In the following screenshot, the only two images used are the user avatar and the blue stamp. Everything else &amp;ndash; the circled question mark, the dark grey arrow next to it, the popover, its shadow and the arrow on top of it &amp;ndash; is pure HTML and CSS.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="CSS Solution - Popover" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/css-overlay-13.png" /&gt;&lt;/figure&gt;&lt;p&gt; Here, you can see how projects in Blossom appear. It&amp;rsquo;s a screenshot of a project&amp;rsquo;s website used as cover on a stack of paper sheets. The paper sheets are implemented with &lt;code&gt;div&lt;/code&gt;s that are rotated using CSS.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="CSS Solution - Stack" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/css-product-cover-14.png" /&gt;&lt;/figure&gt;&lt;p&gt; Also, the circled arrow in the right-hand side of the screenshot below is pure CSS.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="CSS Solution - Circled Arrow" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/css-organization-switcher-15.png" /&gt;&lt;/figure&gt; &lt;/figure&gt;&lt;h3&gt;Tools&lt;/h3&gt;&lt;p&gt; Here are some awesome tools that will help save time when creating effects with CSS.&lt;/p&gt;&lt;ul&gt;&lt;li&gt; &lt;strong&gt;&lt;a
href="http://css3generator.com/" target="_blank"&gt;CSS Generator&lt;/a&gt;:&lt;/strong&gt; Cross browser CSS3 syntax by &lt;a
href="https://twitter.com/RandyJensen"&gt;@RandyJensen&lt;/a&gt;.&lt;/li&gt;&lt;li&gt; &lt;strong&gt;&lt;a
href="http://cssarrowplease.com/" target="_blank"&gt;CSS Arrows:&lt;/a&gt;&lt;/strong&gt; CSS for tooltip arrows by &lt;a
href="https://twitter.com/ShojBerg"&gt;@ShojBerg&lt;/a&gt;.&lt;/li&gt;&lt;li&gt; &lt;strong&gt;&lt;a
href="http://spritecow.com/" target="_blank"&gt;Generating CSS for Sprites&lt;/a&gt;:&lt;/strong&gt; Sprite Cow helps you get the background-position, width and height of sprites within a spritesheet as a nice bit of copyable css. It&amp;rsquo;s built by &lt;a
href="http://theteam.co.uk/" target="_blank"&gt;TheTeam&lt;/a&gt;, and is a real time saver &amp;#8211; definitely worth a try.&lt;/li&gt;&lt;/ul&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="Scalable Vector Graphic" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/svg-16.png" /&gt;&lt;/figure&gt;&lt;p&gt; The primary advantage to &lt;a
href="http://en.wikipedia.org/wiki/Scalable_Vector_Graphics" target="_blank"&gt;SVG&lt;/a&gt; is that, unlike rasterized graphics, they scale reasonably well to various sizes. If you&amp;#8217;re working with simple shapes, they typically are  smaller than PNGs. Often, they are used for things like charts.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="Icon Fonts" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/icon-fonts-17.png" /&gt;&lt;/figure&gt;&lt;p&gt; &lt;a
href="http://weloveiconfonts.com/" target="_blank"&gt;Icon Fonts&lt;/a&gt; are frequently used as a replacement for image sprites. Similar to SVG, they can be scaled up infinitely without any loss of quality and are usually smaller in size, when compared to image sprites. On top of that, you can use CSS to change their size, color and even add effects, such as shadows.&lt;/p&gt;&lt;p&gt; Both SVG and Icon Fonts are well supported by modern browsers.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Retina-Ready Favicons&lt;/h2&gt;&lt;p&gt; Favicons are really important for users who need an easy way to remember which website belongs to which browser tab. A Retina-ready Favicon will not only be easier to identify, but it will also stand out among a crowd of pixelated Favicons that haven&amp;#8217;t yet been optimized.&lt;/p&gt;&lt;p&gt; To make your Favicon Retina-ready, I highly recommend &lt;a
href="http://www.xiconeditor.com/" target="_blank"&gt;X-Icon Editor&lt;/a&gt;. You can either upload a single image and let the editor resize it for different dimensions, or you can upload separate images optimized for each size to get the best results.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="X-Icon Editor" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/x-icon-editor-18.png" width="600" /&gt;&lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;How to Make Existing Images Retina-Ready&lt;/h2&gt;&lt;p&gt; If you want to upgrade a website with existing images, a bit more work is required, as you&amp;#8217;ll need to re-create all images to make them Retina-ready, but this doesn&amp;rsquo;t have to waste too much time.&lt;/p&gt;&lt;p&gt; First, attempt to identify images that you can avoid by using alternatives like CSS, SVG and Image Fonts, as noted previously. Buttons, Icons and other common UI widgets usually can be replaced with modern solutions that don&amp;rsquo;t require any images.&lt;/p&gt;&lt;p&gt; In case you actually need to re-create rasterized images, you&amp;#8217;ll of course want to return to the source files. As you might assume, simply resizing your rasterized bitmap images to be twice as big doesn&amp;rsquo;t get the job done, because all of the details and borders will become pixelated.&lt;/p&gt;&lt;p&gt; No need to despair &amp;ndash; image compositions which mostly contain vectors (i.e. in Adobe Photoshop or Illustrator) are quite easy to scale up. That said, don&amp;rsquo;t forget to verify if your Photoshop effects in the blending options, such as strokes, shadows and bevels, still appear as you intended.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt; In general, making Photoshop compositions directly out of vectors (shapes) and Photoshop&amp;rsquo;s &lt;em&gt;Smart Objects&lt;/em&gt; will save you a great deal of time in the future.&lt;/p&gt;&lt;/blockquote&gt;&lt;hr
/&gt;&lt;h2&gt;How to Optimize the File Size of Images&lt;/h2&gt;&lt;p&gt; Last, but not least, optimizing the file size of all images in an application or website could effectively save up to 90% of image loading times. When it comes to Retina images, the file size reduction gets even more important, as they have a higher pixel density that will increase their respective file sizes.&lt;/p&gt;&lt;p&gt; In Photoshop, you can optimize the image file size, via the &amp;ldquo;Save for Web&amp;rdquo; feature. On top of that, there is an excellent free tool, called &lt;a
href="http://pngmini.com/" target="_blank"&gt;ImageAlpha&lt;/a&gt;, which can reduce the size of your images even more with just a minor loss of quality.&lt;/p&gt;&lt;p&gt; Unlike Photoshop, ImageApha can convert 24-bit alpha channel PNGs to 8-bit PNGs with alpha channel support. The icing on the cake is that these optimized images are cross-browser compatible and even work for IE6!&lt;/p&gt;&lt;p&gt; You can play around with different settings in ImageAlpha to get the right trade-off between quality and file size. In the case below, we can reduce the file size by nearly 80%.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="Image Alpha" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/image-alpha-19.png" width="600" /&gt;&lt;/figure&gt;&lt;p&gt; When you&amp;#8217;re finished setting your desired compression levels, ImageAlpha&amp;rsquo;s save dialog also offers to &amp;ldquo;Optimize with &lt;a
href="http://imageoptim.com/" target="_blank"&gt;ImageOptim&lt;/a&gt;&amp;rdquo; &amp;#8211; another great and free tool.&lt;/p&gt;&lt;p&gt; ImageOptim automatically picks the best compression options for your image and removes unnecessary meta information and color profiles. In the case of our stamp file, ImageOptim was able to reduce the file size by another 34%.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="Image Optim" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/image-optim-20.png" /&gt;&lt;/figure&gt;&lt;p&gt; After we updated all assets at &lt;a
href="https://www.blossom.io" target="_blank"&gt;Blossom.io&lt;/a&gt; for high resolution displays and used ImageAlpha and ImageOptim to optimize the file size, we actually ended up saving a few kilobytes in comparison to the assets we had before.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Save Time, Read This Book&lt;/h2&gt; &lt;figure
class="tutorial_image"&gt;&lt;a
href="http://Retinafy.me/" target="_blank"&gt;&lt;img
alt="Retinafy.me - Retinafy your Websites and Apps" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/retinafy.png" width="200" height="248" /&gt;&lt;/a&gt;&lt;/figure&gt;&lt;p&gt; If you want to learn more about how to get your apps and websites ready for Retina displays, I highly recommend &lt;a
href="http://Retinafy.me/" target="_blank"&gt;&amp;#8220;Retinafy your web sites &amp;amp; apps&amp;#8221;&lt;/a&gt;, by Thomas Fuchs. It&amp;rsquo;s a straight-forward step by step guide that saved me a lot of time and nerves.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Awesome Retina-Ready Sites on the Web&lt;/h2&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="Kickoff" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/kickoff-600.png" /&gt;&lt;br
/&gt;&lt;a
href="http://kickoffapp.com/" target="_blank"&gt;http://kickoffapp.com/&lt;/a&gt;&lt;/figure&gt;&lt;hr
/&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="LayerVault" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/layervault-600.png"&gt;&lt;br
/&gt; &lt;a
href="http://www.layervault.com" target="_blank"&gt;http://www.layervault.com&lt;/a&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;hr
/&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="Apple" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/apple-600.png"&gt;&lt;br
/&gt; &lt;a
href="http://www.apple.com" target="_blank"&gt;http://www.apple.com&lt;/a&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;hr
/&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="Panic" src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/panic-600.png"&gt;&lt;/p&gt;&lt;p&gt;&lt;a
href="http://www.panic.com" target="_blank"&gt;http://www.panic.com&lt;/a&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt;Thanks for reading! Any questions?&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=og52Nv0vAjs:R57WSSnXO78:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=og52Nv0vAjs:R57WSSnXO78:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=og52Nv0vAjs:R57WSSnXO78:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=og52Nv0vAjs:R57WSSnXO78:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=og52Nv0vAjs:R57WSSnXO78:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=og52Nv0vAjs:R57WSSnXO78:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=og52Nv0vAjs:R57WSSnXO78:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=og52Nv0vAjs:R57WSSnXO78:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nettuts/~4/og52Nv0vAjs" height="1" width="1"/&gt;</description> <wfw:commentRss>http://net.tutsplus.com/tutorials/html-css-techniques/the-right-way-to-retinafy-your-websites/feed/</wfw:commentRss> <slash:comments>11</slash:comments> <feedburner:origLink>http://net.tutsplus.com/tutorials/html-css-techniques/the-right-way-to-retinafy-your-websites/</feedburner:origLink></item> <item><title>How to Create a PyroCMS Theme</title><link>http://feedproxy.google.com/~r/nettuts/~3/o44IlSNrSVQ/</link> <comments>http://net.tutsplus.com/tutorials/php/how-to-create-a-pyrocms-theme/#comments</comments> <pubDate>Mon, 20 May 2013 16:00:33 +0000</pubDate> <dc:creator>Zac Vineyard</dc:creator> <category><![CDATA[PHP]]></category> <category><![CDATA[pyrocms]]></category> <guid isPermaLink="false">http://net.tutsplus.com/?p=31771</guid> <description>&lt;a
href='http://rss.buysellads.com/click.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31771&amp;c=2037204739' target='_blank'&gt;&lt;img
src='http://rss.buysellads.com/img.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31771&amp;c=2037204739' border='0' alt='' /&gt;&lt;/a&gt;&lt;p&gt;Like most content management systems, &lt;a
href="https://www.pyrocms.com/"&gt;PyroCMS&lt;/a&gt; uses front-end themes. Though PyroCMS themes are built a bit differently than what you might be used to from other systems, they&amp;#8217;re still quite easy to create. They&amp;#8217;re so easy, in fact, that very little PHP experience is required to assemble them!&lt;/p&gt;&lt;p&gt;&lt;span
id="more-31771"&gt;&lt;/span&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;The Folder Structure&lt;/h2&gt;&lt;p&gt;PyroCMS themes consist of HTML, images, CSS, and JavaScript, arranged into the following supported folders:&lt;/p&gt;&lt;ul&gt;&lt;li&gt; css&lt;/li&gt;&lt;li&gt; img&lt;/li&gt;&lt;li&gt; js&lt;/li&gt;&lt;li&gt; views&lt;/li&gt;&lt;li&gt; views/layouts&lt;/li&gt;&lt;li&gt; views/partials&lt;/li&gt;&lt;li&gt; views/modules&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;While these folders will no doubt look familiar to you, the &amp;quot;views&amp;quot; folder makes the most sense within the context of MVC. When building a theme for PyroCMS, you are really building the views (including assets) of a MVC patterned application. These views consist of a master layout file and multiple partial files (i.e. a &lt;code&gt;header.html&lt;/code&gt; or &lt;code&gt;footer.html&lt;/code&gt;) that shares presentation logic between different layouts. We&amp;#8217;ll discuss this more shortly.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Getting Started&lt;/h2&gt;&lt;p&gt;To get started building your first PyroCMS theme, create the supported folder structure in one of the two places that themes may reside within an instance of PyroCMS:&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;addons/shared_addons/themes (for themes available to all sites)
&lt;/pre&gt;&lt;p&gt;Or:&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;
addons/[site-name]/themes (for themes available to only one specific site)
&lt;/pre&gt;&lt;p&gt;Once you have the base theme folder containing the supported folder structure created, the first file that you&amp;#39;ll want to add to your theme is &lt;code&gt;theme.php&lt;/code&gt;.&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;addons/shared_addons/themes/[my-theme-name]/theme.php
&lt;/pre&gt;&lt;p&gt;This &lt;code&gt;theme.php&lt;/code&gt; file contains all essential details for your theme, including its name, author, version, etc. In a way, this file is similar to the comment block found at the top of a WordPress theme&amp;#39;s &lt;code&gt;style.css&lt;/code&gt; file. Here&amp;#8217;s a basic example of a &lt;code&gt;theme.php&lt;/code&gt; file for your PyroCMS theme:&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;&amp;lt;?php defined('BASEPATH') OR exit('No direct script access allowed');

class Theme_Foo extends Theme
{
    public $name = 'Foo';
    public $author = 'Zac Vineyard';
    public $author_website = 'http://zacvineyard.com';
    public $website = 'http://example.com/themes/foo';
    public $description = 'The antithesis theme to your Bar theme.';
    public $version = '1.0';
}

 /* End of file theme.php */
&lt;/pre&gt;&lt;p&gt;Please take note that this file extends a PyroCMS class, called &lt;code&gt;Theme&lt;/code&gt;. Also, because you are declaring a PHP class in this file, you&amp;#39;ll need to make sure that the name of the folder containing your theme is used in the class declaration. So, if the folder housing your theme is called, &amp;quot;foo,&amp;quot; the class created in your &lt;code&gt;theme.php&lt;/code&gt; should be named, &lt;code&gt;Theme_Foo&lt;/code&gt; (instead of &lt;code&gt;Theme_Custom&lt;/code&gt;, as shown in the example within PyroCMS&amp;#39; documentation).&lt;/p&gt;&lt;p&gt;Once you have created your &lt;code&gt;theme.php&lt;/code&gt; file, you can login to your PyroCMS control panel and view your theme listed in the Themes module.&lt;/p&gt; &lt;figure
class=tutorial_image&gt;&lt;img
src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/pyrocms_theme1.png" alt="Choose a theme in the PyroCMS control panel" width="647" height="407"/&gt;&lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;Layouts&lt;/h2&gt;&lt;p&gt;All layouts files for a PyroCMS theme exist in one of two locations:&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;addons/[site-ref]/themes/[my-theme-name]/views/layouts/
&lt;/pre&gt;&lt;p&gt;Or:&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;
addons/shared_addons/themes/[my-theme-name]/views/layouts/
&lt;/pre&gt;&lt;p&gt;Every theme should have a layout file, named &amp;quot;default.html&amp;quot; in one of the locations listed above. Additional layout files are optional; I&amp;#39;ll show you how to add more layout files in a moment. First, it&amp;#8217;s important to review the contents of a layout file.&lt;/p&gt;&lt;p&gt;Layout files in PyroCMS are built using HTML and a tag parser, referred to as the Lex Tag Parser. This is what a very basic PyroCMS layout file looks like:&lt;/p&gt;&lt;pre class="brush: xml; title: ; notranslate"&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;{{ template:title }}&amp;lt;/title&amp;gt;
    {{ template:metadata }}
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;{{ template:title }}&amp;lt;/h1&amp;gt;
    {{ template:body }}
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;&lt;p&gt;The special tags you see in this bit of HTML are Lex parser tags. If you&amp;#39;ve ever used Smarty templates in PHP, these may look somewhat familiar. The primary benefit to using Lex parser tags in your layout files is that you don&amp;#39;t have to put PHP directly in your views (remember, we&amp;#39;re using MVC), which gives you the best chance of creating PyroCMS themes that follow the &lt;em&gt;don&amp;#8217;t repeat yourself&lt;/em&gt; pattern.&lt;/p&gt;&lt;p&gt;The example that I&amp;#39;ve given above is simple, of course, but Lex parser tags are quite powerful. They can loop through data, work with attributes, and more. &lt;a
href="http://docs.pyrocms.com/2.2/manual/guides/pyrocms-tags"&gt;Learn more about the Lex Parser&lt;/a&gt; in the PyroCMS documentation.&lt;/p&gt;&lt;p&gt;A more complex PyroCMS layout file looks like this:&lt;/p&gt;&lt;pre class="brush: xml; title: ; notranslate"&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;{{ template:title }}&amp;lt;/title&amp;gt;
    {{ template:metadata }}
    {{ theme:favicon file=&amp;quot;favicon.png&amp;quot; }}
    {{ theme:css file=&amp;quot;style.css&amp;quot; }}
    {{ theme:js file=&amp;quot;site.js&amp;quot; }}
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;div class=&amp;quot;header&amp;quot;&amp;gt;
        &amp;lt;div class=&amp;quot;logo&amp;quot;&amp;gt;
            {{ theme:image file=&amp;quot;logo.jpg&amp;quot; alt=&amp;quot;Your Cool Logo&amp;quot; }}
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;nav&amp;quot;&amp;gt;
            {{ navigation:links group=&amp;quot;header&amp;quot; }}
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
        &amp;lt;h1&amp;gt;{{ template:title }}&amp;lt;/h1&amp;gt;
        {{ template:body }}
    &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;&lt;p&gt;You&amp;#39;ll notice that this layout file, using Lex, includes assets, like CSS, JavaScript, and images. Using Lex tags and HTML allows PyroCMS developers to build layout files very quickly.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Partials&lt;/h2&gt;&lt;p&gt;Partials in PyroCMS, which stands for partial layouts, allows you to break layouts into reusable parts or sections. These sections can then be loaded by different layout files. This keeps you from typing the same code (header, footer, etc.) into multiple layout files.&lt;/p&gt;&lt;p&gt;Depending on where you&amp;#39;ve placed your theme files, partials are created in one of two locations:&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;addons/[site-ref]/themes/[my-theme-name]/views/partials/
&lt;/pre&gt;&lt;p&gt;Or:&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;
addons/shared_addons/themes/[my-theme-name]/views/partials/
&lt;/pre&gt;&lt;p&gt;Partials are loaded into layouts using this Lex tag:&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;{{ theme:partial name=&amp;quot;partialname&amp;quot; }}
&lt;/pre&gt;&lt;p&gt;This Lex tag operates exactly like a PHP &lt;code&gt;include&lt;/code&gt; statement &amp;#8211; similar to one that you would find in WordPress or other themes. The code below is a simple example of a PyroCMS layout that takes advantage of partials.&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;{{ theme:partial name=&amp;quot;header&amp;quot; }}

    &amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
        &amp;lt;h1&amp;gt;{{ template:title }}&amp;lt;/h1&amp;gt;
        {{ template:body }}
    &amp;lt;/div&amp;gt;

{{ theme:partial name=&amp;quot;footer&amp;quot; }}
&lt;/pre&gt;&lt;p&gt;The contents of the &lt;code&gt;header.html&lt;/code&gt; partial and &lt;code&gt;footer.html&lt;/code&gt; files are, of course, the HTML we&amp;#39;ll need to reuse from the template in our previous code example above. One quick pointer: there is no limit to the number of partials that you can use in one layout. Additionally, partial files may contain any combination of valid HTML and Lex.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Multiple Layout Files&lt;/h2&gt;&lt;p&gt;To add another layout to your instance of PyroCMS, create one more layout file in your theme&amp;#39;s &lt;em&gt;views/layouts/&lt;/em&gt; directory. This file may receive any name, but it&amp;#8217;s a good idea to name it as descriptively as possible &amp;#8211; like &lt;code&gt;about.html&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;For added flexibility, you can make use of as many layout files as you&amp;#39;d like. When you edit or create a &lt;em&gt;Page Type&lt;/em&gt; in your PyroCMS control panel (&lt;em&gt;Control Panel&amp;rarr;Pages&amp;rarr;Page Types&lt;/em&gt;) and select your desired file from the dropdown, all the layouts in your theme&amp;#39;s layout file will be available to use.&lt;/p&gt; &lt;figure
class=tutorial_image&gt;&lt;img
src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/pyrocms_layout.png" alt="Choose a layout for your PyroCMS page type" width="647" height="407"/&gt;&lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;Mobile Layouts&lt;/h2&gt;&lt;p&gt;PyroCMS is able to easily display separate layouts for mobile and desktops. To use this feature, move your layout files into a folder, called &amp;quot;web&amp;quot; within the &lt;em&gt;views&lt;/em&gt; folder, so that your default layout will be located here:&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;[your-theme]/views/web/layouts/default.html
&lt;/pre&gt;&lt;p&gt;When a user accesses your site using a desktop browser, the primary layout files in this location will be used. If the user accesses your site using a mobile device browser, users will be supplied with the mobile layouts that you&amp;#39;ve created in this location:&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;[your-theme]/views/mobile/layouts/default.html
&lt;/pre&gt;&lt;p&gt;This feature works with multiple layout files.&lt;/p&gt;&lt;p&gt;Please take note of this warning found in the PyroCMS documentation: &amp;quot;PyroCMS does not consider the iPad a mobile device, so it will not load your mobile layouts if the user is accessing your site using an iPad.&amp;quot; If, however, on your site, you&amp;#39;d like to make an iPad recognized as a mobile device, you can change the &amp;quot;user_agent.php&amp;quot; file within the &lt;em&gt;config/&lt;/em&gt; directory to make the iPad recognized a mobile device.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Finished!&lt;/h2&gt;&lt;p&gt;Using this article as a guide, you can see how easy it is to create a theme in PyroCMS. The code examples provided are quite simple, so I encourage you to explore the &lt;a
href="https://www.pyrocms.com/documentation"&gt;PyroCMS documentation&lt;/a&gt; to become more experienced with &lt;a
href="http://docs.pyrocms.com/2.2/manual/guides/themes/theme-layouts"&gt;layouts&lt;/a&gt;, &lt;a
href="http://docs.pyrocms.com/2.2/manual/guides/themes/theme-layouts"&gt;mobile layouts&lt;/a&gt;, &lt;a
href="http://docs.pyrocms.com/2.2/manual/guides/themes/theme-partials"&gt;partials&lt;/a&gt;, and the &lt;a
href="http://docs.pyrocms.com/2.2/manual/guides/pyrocms-tags"&gt;Lex Parser&lt;/a&gt; in PyroCMS. Have fun!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=o44IlSNrSVQ:2SNnvSlZyAI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=o44IlSNrSVQ:2SNnvSlZyAI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=o44IlSNrSVQ:2SNnvSlZyAI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=o44IlSNrSVQ:2SNnvSlZyAI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=o44IlSNrSVQ:2SNnvSlZyAI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=o44IlSNrSVQ:2SNnvSlZyAI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=o44IlSNrSVQ:2SNnvSlZyAI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=o44IlSNrSVQ:2SNnvSlZyAI:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nettuts/~4/o44IlSNrSVQ" height="1" width="1"/&gt;</description> <wfw:commentRss>http://net.tutsplus.com/tutorials/php/how-to-create-a-pyrocms-theme/feed/</wfw:commentRss> <slash:comments>7</slash:comments> <feedburner:origLink>http://net.tutsplus.com/tutorials/php/how-to-create-a-pyrocms-theme/</feedburner:origLink></item> <item><title>The Linux Firewall</title><link>http://feedproxy.google.com/~r/nettuts/~3/YjnBJVTS5AU/</link> <comments>http://net.tutsplus.com/tutorials/other/the-linux-firewall/#comments</comments> <pubDate>Fri, 17 May 2013 18:00:48 +0000</pubDate> <dc:creator>Patkos Csaba</dc:creator> <category><![CDATA[Other]]></category> <category><![CDATA[linux]]></category> <guid isPermaLink="false">http://net.tutsplus.com/?p=31748</guid> <description>&lt;a
href='http://rss.buysellads.com/click.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31748&amp;c=1751648120' target='_blank'&gt;&lt;img
src='http://rss.buysellads.com/img.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31748&amp;c=1751648120' border='0' alt='' /&gt;&lt;/a&gt;&lt;p&gt;There are several firewall applications for Linux, but what you may not realize is that, at the heart of all these programs is a single all-mighty application that is built right into the Linux Kernel: iptables. This is the Linux firewall. No matter which program you use to configure your firewall under Linux, it ultimately all comes down to iptables. All that these other programs do is configure it.&lt;/p&gt;&lt;p&gt;So, here comes the question: if those programs simply configure iptables, why not simply configure it directly yourself? Doing so is easier than you might think!&lt;/p&gt;&lt;p&gt;&lt;span
id="more-31748"&gt;&lt;/span&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Networking Background&lt;/h2&gt;&lt;p&gt;If you&amp;#8217;re familiar with networking terms, like connections, IP, TCP, and Port, then feel free to skip ahead to the next step. Otherwise, if you&amp;#8217;re new to networking, read on to familiarize yourself with the terms that you will need to understand, in order to follow along with this tutorial.&lt;/p&gt;&lt;p&gt;Please note that the terms and definitions below have been intentionally over-simplified. They&amp;#8217;re meant for every-day users, not sysadmins. So if you are a seasoned sysadmin or you have a CCNA in you pocket, please excuse me for not entering into the details.&lt;br
/&gt;&lt;h3&gt;TCP/IP&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;TCP/IP&lt;/strong&gt; is a protocol that allows computers to communicate with one another over Internet and Ethernet Networks.&lt;/p&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; Failure is the last resort.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Imagine an &lt;strong&gt;Ethernet Network&lt;/strong&gt; as a small local network (LAN &amp;#8211; local area network), like your home PC, laptop, and smart phone. It&amp;#8217;s a small heterogeneous network that is isolated from the rest of the world. A network of such networks is what we all know as the &lt;strong&gt;Internet&lt;/strong&gt;: a set of interconnected networks.&lt;/p&gt;&lt;p&gt;TCP/IP is a combination of two protocols working at different levels in the hierarchy of the network communication chain. We won&amp;#8217;t delve into details about that hierarchy. &lt;strong&gt;TCP&lt;/strong&gt; stands for &lt;em&gt;Transfer Control Protocol&lt;/em&gt;, and its core responsibility is to ensure that communication is successful. It controls the correctness of the data sent, and ensures its success. It has different algorithms to perform sophisticated checksums, autocorrect, and retry. Failure is the last resort. The name, &lt;strong&gt;IP&lt;/strong&gt; comes from Internet Protocol. You can best associate it with the &amp;#8220;phone-number&amp;#8221; of your PC. Each machine capable of communicating over the Internet must have an IP address &amp;#8211; a unique phone number &amp;#8211; so that communication packets can find their destinations. A &lt;strong&gt;packet&lt;/strong&gt; is a small piece of data inside a communication stream, which is self contained and can be checked for correctness. Essentially, we can say that our computers send TCP packets over the Internet using the IP protocol.&lt;/p&gt;&lt;p&gt;Each network communication is bound to a specific &lt;strong&gt;port&lt;/strong&gt;. Network ports range from 0 to 2^16 (65536). Each network connection has an outgoing port for the one who initiates it, and an inbound port for the one who is listening for other computers&amp;#8217; messages. There can be several connections between several computers over identical ports. A computer can, however, talk over several ports at once. So, basically, ports are good to identify services and define channels of communications, but they do not limit the amount of data or connections.&lt;/p&gt;&lt;p&gt;Some computers can have similar IP addresses. You may have observed that both your computer at home and at work have IP addresses that takes the form of something along the lines of &lt;code&gt;192.168.something.something&lt;/code&gt;, or &lt;code&gt;10.0.something.something&lt;/code&gt;, or &lt;code&gt;172.16.something.something&lt;/code&gt;. These are the so-called private IP addresses that can be used only inside your LAN. You can&amp;#8217;t go out to the Internet with IP addresses like this. They are akin to interior numbers for your company&amp;#8217;s phone network.&lt;/p&gt;&lt;h3&gt;Gateway &amp;#038; Bridge&lt;/h3&gt;&lt;p&gt;A &lt;strong&gt;Bridge&lt;/strong&gt; is what computers with real (public) IP addresses pass to the Internet.&lt;/p&gt; &lt;figure
class=tutorial_image&gt;&lt;img
src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/bridge.png" alt="The bridge" width="600"/&gt;&lt;/figure&gt;&lt;p&gt;Essentially, these computers have the rights and capabilities to talk to one another on the Internet directly. But, since there are no direct connections between all the computers in the world (that would be quite hard to accomplish), bridges are responsible for connecting segments of the Internet.&lt;/p&gt;&lt;p&gt;Keeping our telephony analogy alive, you can imagine these bridges to be similar to the telephone centers in your town or neighborhood. If you make a call to another local number (the computers on the left in our schema), the communication could have been made directly by your telephone center by physically connecting your line with you neighbor&amp;#8217;s. However, if you instead want  to call your distant uncle Bob, your call would have to be redirected over several phone centers until your uncle&amp;#8217;s phone could be connected. These form a &lt;em&gt;bridge&lt;/em&gt; between your town and his town.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;A &lt;strong&gt;Gateway&lt;/strong&gt; is a way for computers from a private network (LAN with private IP addresses) to communicate with other computers on the Internet.&lt;/p&gt;&lt;/blockquote&gt; &lt;figure
class=tutorial_image&gt;&lt;img
src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/gateway.png" alt="Gateway" width="600"/&gt;&lt;/figure&gt;&lt;p&gt;A private network is like your company&amp;#8217;s private phone network. You can call interior numbers, but in order to call someone who is outside of your company&amp;#8217;s network &amp;#8211; like your wife at home &amp;#8211; you must first dial a special number or prefix.&lt;/p&gt;&lt;p&gt;Computers actually function in a similar way. When you are on a private network, you have a so-called gateway computer. When your computer attempts to talk to another computer on the Internet, it will &lt;em&gt;automagically&lt;/em&gt; contact the gateway first and request &amp;#8220;a line&amp;#8221; to the outside world. The gateway will do the talking to the computer found on the Internet, and will forward the message back to your computer. You, as an ordinary user, see no difference between a bridge and a gateway. Your computer will know how to deal with them.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Definition of a Firewall&lt;/h2&gt;&lt;p&gt;A firewall is a program running on a Gateway, Bridge or PC/Laptop/Smartphone that is capable of filtering incoming, outgoing, and forwarded network packets. A firewall is essentially a tool that lets you restrict you or your network&amp;#8217;s access to the Internet, and someone else&amp;#8217;s access from the Internet to your network.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;And yes, your cable router or home Wi-Fi is, in fact, a firewall for all your computers and gadgets that connect to the internet through it.&lt;/p&gt;&lt;/blockquote&gt;&lt;hr
/&gt;&lt;h2&gt;The Problem We Will Solve&lt;/h2&gt;&lt;p&gt;To set the context, let&amp;#8217;s imagine a very possible network architecture. I&amp;#8217;ve seen many small companies running something similar to this.&lt;/p&gt; &lt;figure
class=tutorial_image&gt;&lt;img
src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/network.png" alt="Network" width="600"/&gt;&lt;/figure&gt;&lt;p&gt;What we have here is actually something quite simple:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;A few computers and other network-connected devices &amp;#8211; the green boxes&lt;/li&gt;&lt;li&gt;An e-mail server &amp;#8211; the red box&lt;/li&gt;&lt;li&gt;A Microsoft Active Directory server &amp;#8211; the blue box&lt;/li&gt;&lt;li&gt;A gateway, which is also a firewall, for our network running Linux &amp;#8211; the black box&lt;/li&gt;&lt;li&gt;Between all of these is a simple network switch&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In the following section, we will configure iptables on that gateway, so that it will allow all the devices in the network to connect to the Internet. It will allow us to connect to it, via SSH, and will allow external mail servers to reach the mail server inside our network &amp;#8211; a computer that does not even have a public IP address; only a private one.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Iptables Components&lt;/h2&gt;&lt;p&gt;Iptables&amp;#8217; name actually has a meaning in its functionality. It&amp;#8217;s a set of tables of IP address and ports with some actions attached to them. In iptable&amp;#8217;s terms, these tables are referred to as &lt;i&gt;chains&lt;/i&gt;. An unconfigured, empty iptables might look like this:&lt;/p&gt;&lt;pre class="brush: bash; title: ; notranslate"&gt;csaba ~ # iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         &lt;/pre&gt;&lt;p&gt;You can observe that there are three main chains:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;INPUT&lt;/strong&gt; &amp;#8211; all incoming connections&lt;/li&gt;&lt;li&gt;&lt;strong&gt;FORWARD&lt;/strong&gt; &amp;#8211; connections passing through&lt;/li&gt;&lt;li&gt;&lt;strong&gt;OUTPUT&lt;/strong&gt; &amp;#8211; connections departing from this server&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The term, &amp;#8220;&lt;em&gt;policy ACCEPT&lt;/em&gt;&amp;#8221; in parenthesis means that ACCEPT is set as the default policy for that particular chain. So, when there is no match for a connection, that rule will be applied. There are three main concepts you can use when configuring your firewall:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;default policy ACCEPT &amp;#038; deny selectively all you need to&lt;/strong&gt; &amp;#8211; it may be difficult to specify all that it is denied. I do not recommend this approach.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;default policy DROP or REJECT &amp;#038; allow selectively all you need to&lt;/strong&gt; &amp;#8211; this is better, but it has a problem. If you make a mistake in your iptables configuration, you can easily remain with empty chains denying access to everything and everyone, including you. So, unless you always have physical access to your firewall server/computer, I recommend that you use the next approach.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;default policy ACCEPT &amp;#038; an explicit policy to DROP all &amp;#038; then allow selectively all you need&lt;/strong&gt; &amp;#8211; this is a combined solution between the first two possibilities. It will use an ACCEPT default policy, so if something goes wrong, you can log back over SSH or whatever remote connection you use for your firewall. At the same time, an explicit DROP rule for any unmatched connections ensures that you are safe. Allowing only what you know about and actually need to use offers the best possible protection.&lt;/li&gt;&lt;/ul&gt;&lt;hr
/&gt;&lt;h2&gt;Adding Rules to Iptables&lt;/h2&gt;&lt;p&gt;There are two ways to add a new rule to iptables. One is to insert it at the begining of a chain. The other option is to append it to the end of a chain. Why does it matter in which order the rules occur?&lt;/p&gt;&lt;div
class="tip-shortcode"&gt;&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; iptables check the rules in a chain from top to bottom. It will stop its search at the first match.&lt;/p&gt;&lt;/div&gt;&lt;p&gt;You must design your rules in such a way to consider the above mentioned behavior of iptables. After the first match of a rule, iptables will take the actions specified by the rule, and then cease the search. If no rule matches the connection that is checked, the default policy applies.&lt;/p&gt;&lt;h3&gt;Inserting a New Rule&lt;/h3&gt;&lt;p&gt;Let&amp;#8217;s say that we want to add a rule to our iptables that will allow anyone to connect to port 22 on our firewall. Port 22 is the port for the SSH protocol. Of course, a good server admin will change this port to something unexpected for obvious security/obscurity reasons, but that&amp;#8217;s another story for another tutorial. We will stick with 22.&lt;/p&gt;&lt;pre class="brush: bash; title: ; notranslate"&gt;csaba ~ # iptables -I INPUT -i eth0 -p tcp --dport 22 -j ACCEPT
csaba ~ # iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh&lt;/pre&gt;&lt;p&gt;I presumed that the IP address facing the Internet with the public IP on it is on the network interface, called &lt;code&gt;eth0&lt;/code&gt;. Let&amp;#8217;s dissect this command:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;-&lt;strong&gt;I&lt;/strong&gt; &amp;#8211; stands for insert the rule&lt;/li&gt;&lt;li&gt; &lt;strong&gt;INPUT&lt;/strong&gt; &amp;#8211; specifies the desired chain&lt;/li&gt;&lt;li&gt; &lt;strong&gt;-i&lt;/strong&gt; &amp;#8211; stands for network interface &amp;#8211; in our case, &lt;code&gt;eth0&lt;/code&gt;&lt;/li&gt;&lt;li&gt; &lt;strong&gt;-p&lt;/strong&gt; &amp;#8211; is for protocol (tcp or udp)&lt;/li&gt;&lt;li&gt; &lt;strong&gt;&amp;#8211;dport 22&lt;/strong&gt; &amp;#8211; is for destination port 22 &amp;#8211; it has a corresponding &lt;code&gt;--sport&lt;/code&gt; version for source port verification&lt;/li&gt;&lt;li&gt; &lt;strong&gt;-j&lt;/strong&gt; &amp;#8211; actually comes from &amp;#8220;jump,&amp;#8221; and is followed by an action -in our case, the action to accept the connection&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;However, you may have already guessed that this rule has little effect at this time. Our default policy is ACCEPT, so accepting something explicitly does not offer us any extra functionality. Now, remember the third recommended way to set up our firewall: the explicit rule to deny everything not matched. Let&amp;#8217;s add that rule.&lt;/p&gt;&lt;h3&gt;Appending Rules&lt;/h3&gt;&lt;p&gt;We want to append a rule that blocks incoming traffic. But be careful: we only want to block what could be harmful. If we block everything, we will not be able to do anything, because the replies to our requests will be rejected. For example, when you browse a web page, you make a request, then you receive an answer. This answer comes into your computer, so, on the INPUT chain, we must have a rule to allow it.&lt;/p&gt;&lt;p&gt;First, we will append a rule to accept incoming traffic for already established connections, such as responses to requests.&lt;/p&gt;&lt;pre class="brush: bash; title: ; notranslate"&gt;csaba ~ # iptables -A INPUT -i eth0 -m conntrack  --ctstate ESTABLISHED,RELATED -j ACCEPT
csaba ~ # iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED&lt;/pre&gt;&lt;p&gt;Now that we&amp;#8217;ve safeguarded our existing connections and the replies to the connections we initiated, we can deny everything else that wasn&amp;#8217;t matched.&lt;/p&gt;&lt;pre class="brush: bash; title: ; notranslate"&gt;csaba ~ # iptables -A INPUT -i eth0 -p tcp -j DROP
csaba ~ # iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
DROP       tcp  --  anywhere             anywhere
&lt;/pre&gt;&lt;p&gt;We&amp;#8217;ve appended another line, with a rule to DROP all connections that match. Remember: this rule will only apply if none of the previous ones actually match.&lt;/p&gt;&lt;p&gt;There are two ways to refuse a connections.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;You can use DROP, which is equivalent to dialing a non-existent phone number with the difference that, after some time, the network connection times out. With a phone number, a robot informs you that the number does not exist. But the end result from the point of view of the caller is the same: it thinks that the destination does not exist.&lt;/p&gt;&lt;li&gt;The second way to refuse the connection is with the rule, REJECT, and an optional message. This is analogous to the number you are trying to call being busy. You may know that there is a number, you know it can be called, but it simply refuses to take your calls. Optionally, you can provide a message with a REJECT rule; the default is &amp;#8220;ICMP port unreachable&amp;#8221; or something similar.&lt;/ol&gt;&lt;hr
/&gt;&lt;h2&gt;Allow Computers to Access the Internet&lt;/h2&gt;&lt;p&gt;At this point, we have some basic rules for the INPUT chain. But we have a network of computers having private IP addresses. We need to provide a gateway to the Internet. This is also done by iptables: the firewall.&lt;/p&gt;&lt;h3&gt;Network Address Translation (NAT)&lt;/h3&gt;&lt;p&gt;Likely, you&amp;#8217;ve already heard this term: NAT. This refers to the procedure of translating one network address to another and forwarding the information between the two. It&amp;#8217;s most frequently used in architectures like our own. The gateway has to do NAT in order to translate any computer&amp;#8217;s IP from the LAN into its own public IP and then back.&lt;/p&gt;&lt;p&gt;Routing is the procedure by which a system can figure out on what network interfaces and toward what gateway it can communicate to reach its destination. Each computer has a routing table of its own to determine this. Iptables can hook into this routing procedure at two different points: before and after the procedure has occurred.&lt;/p&gt;&lt;h3&gt;Nating with Iptables&lt;/h3&gt;&lt;pre class="brush: bash; title: ; notranslate"&gt;csaba ~ # iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 89.72.31.243&lt;/pre&gt;&lt;p&gt;This command adds a rule as POSTROUTING to the NATing table (&lt;code&gt;-t nat&lt;/code&gt;). POSTROUTING essentially means that the packets first pass the routing mechanism on the gateway, and, only after that are they modified. The rule &lt;code&gt;-j SNAT&lt;/code&gt; means Source NAT; the source address of the packets will be changed to the address on the interface specified by &lt;code&gt;-o eth0&lt;/code&gt; &amp;#8211; in our case, to the IP address specified by the option, &lt;code&gt;--to-source&lt;/code&gt;. So, anyone contacted by a computer in your network will assume that it is talking directly to your gateway. It will have absolutely no clue about the fact that the packets are destined for some different computer. The gateway, using iptables, will keep an internal list of all the translated IP addresses, and, when a reply comes, it will revert the change and pass the answer to the computer inside the network.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Allow Client from the Internet to the Email Server&lt;/h2&gt;&lt;p&gt;Another problem that we face is what to do when we have a server that is behind a firewall. We need to allow the clients, coming from the Internet, to communicate with our server in some way. This is the case with our mail server. When an email arrives that has to be delivered to a mail account on our server, the sending email server will have to connect to our receiving one.&lt;/p&gt;&lt;p&gt;But our mail server only has a private IP address. There is no way that an external computer could connect to it directly. On the other hand, our gateway has an external IP that anyone could connect to. The solution? Open a port on our gateway so that a request from the Internet to that port will actually go to our email server. The answer, of course, will travel through the gateway back to the client. The trick is to use a different type of NAT here, called Destination NAT. This changes the packets destination and then reverts them back when the response occurs. Think of DNAT as the reverse of SNAT.&lt;/p&gt;&lt;div
class="tip-shortcode"&gt;&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; You may know this feature as &amp;#8220;Virtual Server,&amp;#8221; if you&amp;#8217;ve ever played around with small home routers.&lt;/p&gt;&lt;/div&gt;&lt;pre class="brush: bash; title: ; notranslate"&gt;csaba ~ # iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 25 -j DNAT --to-destination 192.168.1.2:25&lt;/pre&gt;&lt;p&gt;So, what is happening here? A packet comes in to our gateway at the port 25 (the port used for SMTP, the email protocol the whole Internet uses). The rule above catches this packet because of the &lt;code&gt;--dport 25&lt;/code&gt; option, which basically says, &amp;#8220;&lt;em&gt;Match anything that goes to this port on the interface specified by &lt;code&gt;-i eth0&lt;/code&gt;. Now that the packet is matched, change its destination from the current machine (the gateway) to the one specified by &lt;code&gt;--to-destination&lt;/code&gt;.&lt;/em&gt;&amp;#8221; Please note that you can specify the port explicitly after the IP address by separating it with a colon.&lt;/p&gt;&lt;p&gt;Finally, note that this is in the PREROUTING hook. The destination has to be changed before the routing actually takes place. Otherwise, the packets would end up on the gateway and find no way to the mail server.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Persisting iptables Configuration&lt;/h2&gt;&lt;p&gt;The rules you insert or append to iptables are in memory. After a reboot, spoof: everything is gone! To save your configuration, you should dump it into a file, like so:&lt;/p&gt;&lt;pre class="brush: bash; title: ; notranslate"&gt;csaba ~ # iptables-save &amp;gt; /some/directory/my_rules.fw&lt;/pre&gt;&lt;p&gt;The file&amp;#8217;s name doesn&amp;#8217;t matter, nor does its extension. To restore the rules, run this command when your computer starts.&lt;/p&gt;&lt;pre class="brush: bash; title: ; notranslate"&gt;iptables-restor &amp;lt; /some/directory/my_rules.fw&lt;/pre&gt;&lt;p&gt;If you take a look at the saved content, you&amp;#8217;ll see that they&amp;#8217;re the same parameters that we used with the iptables commands. There are some minor differences, but you can easily understand the saved file, and could even write your own such files by hand and load them.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Final Thoughts&lt;/h2&gt;&lt;p&gt;In closing, here are some thoughts on when and when not to use a firewall with a Linux computer.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Use a firewall&lt;/strong&gt; on Linux when you configure a server (like a gateway in our example), or when you have a computer with important information on it that is directly exposed to the Internet. Before you jump on to configure your iptables, consider the potential danger. Ask yourself: is my computer known on the Internet? There are a few billion computers out there. If yours is just one, the chance of being targeted is incredibly low. Are there people directly interested in your information? Hackers don&amp;#8217;t waste time stealing random data in the hopes that they might find something. They usually know what they are looking for, and then target the computers containing the desired information. Of course, there are countless attacks against random computers that attempt to install some kind of worm or virus, but on Linux, you are immune by design.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Don&amp;#8217;t waste your time&lt;/strong&gt; with configuring a firewall on Linux when it is a computer that is alway behind a firewall, such as your home PC behind your home router, or when you have no particularly important information on your laptop. If you keep the services that listen on the network to a minimum and have a decently secure password, you can forget your firewall. I personally have no personal computer, laptop or smartphone with a firewall running. I have, however, a home router with a well-configured firewall.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;I think you can safely apply these ideas to Mac OSX as well. If you&amp;#8217;re a Windows user, sorry: a firewall is your first line of defense. For Linux or MacOSX, though, a firewall is your last line of defense. A  carefully selected password and not running useless services should handle the bulk of your computer&amp;#8217;s protection.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Thanks for reading. Questions?&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=YjnBJVTS5AU:G3Xi0DKl-7M:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=YjnBJVTS5AU:G3Xi0DKl-7M:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=YjnBJVTS5AU:G3Xi0DKl-7M:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=YjnBJVTS5AU:G3Xi0DKl-7M:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=YjnBJVTS5AU:G3Xi0DKl-7M:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=YjnBJVTS5AU:G3Xi0DKl-7M:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=YjnBJVTS5AU:G3Xi0DKl-7M:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=YjnBJVTS5AU:G3Xi0DKl-7M:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nettuts/~4/YjnBJVTS5AU" height="1" width="1"/&gt;</description> <wfw:commentRss>http://net.tutsplus.com/tutorials/other/the-linux-firewall/feed/</wfw:commentRss> <slash:comments>14</slash:comments> <feedburner:origLink>http://net.tutsplus.com/tutorials/other/the-linux-firewall/</feedburner:origLink></item> <item><title>Tuts+ Premium Cash Back Offer: 3 Days to Go</title><link>http://feedproxy.google.com/~r/nettuts/~3/mH16lMPEuDo/</link> <comments>http://net.tutsplus.com/articles/news/tuts-premium-cash-back-offer-3-days-to-go/#comments</comments> <pubDate>Fri, 17 May 2013 17:00:56 +0000</pubDate> <dc:creator>Joel Bankhead</dc:creator> <category><![CDATA[News]]></category> <guid isPermaLink="false">http://net.tutsplus.com/?p=31722</guid> <description>&lt;a
href='http://rss.buysellads.com/click.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31722&amp;c=690135492' target='_blank'&gt;&lt;img
src='http://rss.buysellads.com/img.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31722&amp;c=690135492' border='0' alt='' /&gt;&lt;/a&gt;&lt;p&gt;&lt;strong&gt;This offer ends soon! Act now and don’t miss out on cash back when trying a monthly Tuts+ Premium subscription.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;At $19 a month, Tuts+ Premium is fantastic value. But it&amp;#8217;s even better when we hand your first $19 right back to you!&lt;/p&gt;&lt;p&gt;For a limited time, we&amp;#8217;re offering $19 cash back to new Tuts+ Premium monthly subscribers when signing up via PayPal. If you’ve been thinking about checking out our extensive library of courses, tutorials, eBooks and guides there’s never been a better time to join up and dive in.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;This offer ends at noon on the 20th of May AEST, so act fast.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;a
href="https://tutsplus.com/paypal-cash-back-offer/?utm_source=nettutsend&amp;#038;utm_medium=post&amp;#038;utm_campaign=paypal_cashback&amp;#038;wt.mc_id=paypal"&gt;Become a Tuts+ Premium Member and take your creative &amp;#038; technical skills to a new level.&lt;/a&gt;&lt;br
/&gt; &lt;span
id="more-31722"&gt;&lt;/span&gt;&lt;/p&gt;&lt;hr
/&gt; What can you learn on Tuts+ Premium? Glad you asked! Currently, more than 15,000 members are sharpening their skills in a wide range of areas including web design, web development, Photoshop, vectors, video effects, and many more. With Tuts+ Premium you learn from expert instructors in every field.&lt;/p&gt;&lt;p&gt;Join now and get instant access to your very own library of courses, tutorials, and eBooks, available whenever you need them. Become part of a community of over 15,000 members and start getting better at the skills you care about. Our dedicated team adds new content weekly, so there&amp;#8217;s always something fresh to sink your teeth into.&lt;/p&gt;&lt;p&gt;&lt;a
href="https://tutsplus.com/paypal-cash-back-offer/?utm_source=nettutsend&amp;#038;utm_medium=post&amp;#038;utm_campaign=paypal_cashback&amp;#038;wt.mc_id=paypal"&gt;Join Tuts+ Premium&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=mH16lMPEuDo:yBmtqhdwOjQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=mH16lMPEuDo:yBmtqhdwOjQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=mH16lMPEuDo:yBmtqhdwOjQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=mH16lMPEuDo:yBmtqhdwOjQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=mH16lMPEuDo:yBmtqhdwOjQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=mH16lMPEuDo:yBmtqhdwOjQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=mH16lMPEuDo:yBmtqhdwOjQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=mH16lMPEuDo:yBmtqhdwOjQ:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nettuts/~4/mH16lMPEuDo" height="1" width="1"/&gt;</description> <wfw:commentRss>http://net.tutsplus.com/articles/news/tuts-premium-cash-back-offer-3-days-to-go/feed/</wfw:commentRss> <slash:comments>2</slash:comments> <feedburner:origLink>http://net.tutsplus.com/articles/news/tuts-premium-cash-back-offer-3-days-to-go/</feedburner:origLink></item> <item><title>How to Write Testable and Maintainable Code in PHP</title><link>http://feedproxy.google.com/~r/nettuts/~3/l6VzPp300us/</link> <comments>http://net.tutsplus.com/tutorials/php/how-to-write-testable-and-maintainable-code-in-php/#comments</comments> <pubDate>Wed, 15 May 2013 20:08:11 +0000</pubDate> <dc:creator>Chris Fidao</dc:creator> <category><![CDATA[PHP]]></category> <category><![CDATA[tdd]]></category> <guid isPermaLink="false">http://net.tutsplus.com/?p=31726</guid> <description>&lt;a
href='http://rss.buysellads.com/click.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31726&amp;c=1237422516' target='_blank'&gt;&lt;img
src='http://rss.buysellads.com/img.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31726&amp;c=1237422516' border='0' alt='' /&gt;&lt;/a&gt;&lt;p&gt;Frameworks provide a tool for rapid application development, but often accrue technical debt as rapidly as they allow you to create functionality. Technical debt is created when maintainability isn&amp;#39;t a purposeful focus of the developer. Future changes and debugging become costly, due to a lack of unit testing and structure.&lt;/p&gt;&lt;p&gt;Here&amp;#39;s how to begin structuring your code to achieve testability and maintainability &amp;#8211; and save you time.&lt;/p&gt;&lt;p&gt;&lt;span
id="more-31726"&gt;&lt;/span&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;We&amp;#39;ll Cover (loosely)&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;DRY&lt;/li&gt;&lt;li&gt;Dependency Injection&lt;/li&gt;&lt;li&gt;Interfaces&lt;/li&gt;&lt;li&gt;Containers&lt;/li&gt;&lt;li&gt;Unit Tests with PHPUnit&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Let&amp;#39;s begin with some contrived, but typical code. This might be a model class in any given framework.&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;
class User {

public function getCurrentUser()
{
    $user_id = $_SESSION['user_id'];

    $user = App::db-&amp;gt;select('id, username')
                    -&amp;gt;where('id', $user_id)
                    -&amp;gt;limit(1)
                    -&amp;gt;get();

    if ( $user-&amp;gt;num_results() &amp;gt; 0 )
    {
            return $user-&amp;gt;row();
    }

    return false;
}

}
&lt;/pre&gt;&lt;p&gt;This code will work, but needs improvement:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;This isn&amp;#39;t testable.&lt;ul&gt;&lt;li&gt;We&amp;#39;re relying on the &lt;code&gt;$_SESSION&lt;/code&gt; global variable. Unit-testing frameworks, such as PHPUnit, rely on the command-line, where &lt;code&gt;$_SESSION&lt;/code&gt; and many other global variables aren&amp;#39;t available.&lt;/li&gt;&lt;li&gt;We&amp;#39;re relying on the database connection. Ideally, actual database connections should be avoided in a unit-test. Testing is about code, not about data.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;This code isn&amp;#39;t as maintainable as it could be. For instance, if we change the data source, we&amp;#39;ll need to change the database code in every instance of &lt;code&gt;App::db&lt;/code&gt; used in our application. Also, what about instances where we don&amp;#39;t want just the current user&amp;#39;s information?&lt;/li&gt;&lt;/ol&gt;&lt;h4&gt;An Attempted Unit Test&lt;/h4&gt;&lt;p&gt;Here&amp;#39;s an attempt to create a unit test for the above functionality.&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;
class UserModelTest extends PHPUnit_Framework_TestCase {

    public function testGetUser()
    {
        $user = new User();

        $currentUser = $user-&amp;gt;getCurrentUser();

        $this-&amp;gt;assertEquals(1, $currentUser-&amp;gt;id);
    }

}
&lt;/pre&gt;&lt;p&gt;Let&amp;#39;s examine this. First, the test will fail. The &lt;code&gt;$_SESSION&lt;/code&gt; variable used in the &lt;code&gt;User&lt;/code&gt; object doesn&amp;#39;t exist in a unit test, as it runs PHP in the command line.&lt;/p&gt;&lt;p&gt;Second, there&amp;#39;s no database connection setup. This means that, in order to make this work, we will need to bootstrap our application in order to get the &lt;code&gt;App&lt;/code&gt; object and its &lt;code&gt;db&lt;/code&gt; object. We&amp;#39;ll also need a working database connection to test against.&lt;/p&gt;&lt;p&gt;To make this unit test work, we would need to:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Setup a config setup for a CLI (PHPUnit) run in our application&lt;/li&gt;&lt;li&gt;Rely on a database connection. Doing this means relying on a data source separate from our unit test. What if our test database doesn&amp;#39;t have the data we&amp;#39;re expecting? What if our database connection is slow?&lt;/li&gt;&lt;li&gt;Relying on an application being bootstrapped increases the overhead of the tests, slowing the unit tests down dramatically. Ideally, most of our code can be tested independent of the framework being used.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;So, let&amp;#39;s get down to how we can improve this.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Keep Code DRY&lt;/h2&gt;&lt;p&gt;The function retrieving the current user is unnecessary in this simple context. This is a contrived example, but in the spirit of DRY principles, the first optimization I&amp;#39;m choosing to make is to generalize this method.&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;
class User {

    public function getUser($user_id)
    {
        $user = App::db-&amp;gt;select('user')
                        -&amp;gt;where('id', $user_id)
                        -&amp;gt;limit(1)
                        -&amp;gt;get();

        if ( $user-&amp;gt;num_results() &amp;gt; 0 )
        {
            return $user-&amp;gt;row();
        }

        return false;
    }

}
&lt;/pre&gt;&lt;p&gt;This provides a method we can use across our entire application. We can pass in the current user at the time of the call, rather than passing that functionality off to the model. Code is more modular and maintainable when it doesn&amp;#39;t rely on other functionalities (such as the session global variable).&lt;/p&gt;&lt;p&gt;However, this is still not testable and maintainable as it could be. We&amp;#39;re still relying on the database connection.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Dependency Injection&lt;/h2&gt;&lt;p&gt;Let&amp;#39;s help improve the situation by adding some Dependency Injection. Here&amp;#39;s what our model might look like, when we pass the database connnection into the class.&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;
class User {

    protected $_db;

    public function __construct($db_connection)
    {
        $this-&amp;gt;_db = $db_connection;
    }

    public function getUser($user_id)
    {
        $user = $this-&amp;gt;_db-&amp;gt;select('user')
                        -&amp;gt;where('id', $user_id)
                        -&amp;gt;limit(1)
                        -&amp;gt;get();

        if ( $user-&amp;gt;num_results() &amp;gt; 0 )
        {
            return $user-&amp;gt;row();
        }

        return false;
    }

}
&lt;/pre&gt;&lt;p&gt;Now, the dependencies of our &lt;code&gt;User&lt;/code&gt; model are provided for. Our class no longer assumes a certain database connection, nor relies on any global objects.&lt;/p&gt;&lt;p&gt;At this point, our class is basically testable. We can pass in a data-source of our choice (mostly) and a user id, and test the results of that call. We can also switch out separate database connections (assuming that both implement the same methods for retrieving data). Cool.&lt;/p&gt;&lt;p&gt;Let&amp;#39;s look at what a unit test might look like for that.&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;
&amp;lt;?php

use Mockery as m;
use Fideloper\User;

class SecondUserTest extends PHPUnit_Framework_TestCase {

    public function testGetCurrentUserMock()
    {
        $db_connection = $this-&amp;gt;_mockDb();

        $user = new User( $db_connection );

        $result = $user-&amp;gt;getUser( 1 );

        $expected = new StdClass();
        $expected-&amp;gt;id = 1;
        $expected-&amp;gt;username = 'fideloper';

        $this-&amp;gt;assertEquals( $result-&amp;gt;id, $expected-&amp;gt;id, 'User ID set correctly' );
        $this-&amp;gt;assertEquals( $result-&amp;gt;username, $expected-&amp;gt;username, 'Username set correctly' );
    }

    protected function _mockDb()
    {
        // &amp;quot;Mock&amp;quot; (stub) database row result object
        $returnResult = new StdClass();
        $returnResult-&amp;gt;id = 1;
        $returnResult-&amp;gt;username = 'fideloper';

        // Mock database result object
        $result = m::mock('DbResult');
        $result-&amp;gt;shouldReceive('num_results')-&amp;gt;once()-&amp;gt;andReturn( 1 );
        $result-&amp;gt;shouldReceive('row')-&amp;gt;once()-&amp;gt;andReturn( $returnResult );

        // Mock database connection object
        $db = m::mock('DbConnection');

        $db-&amp;gt;shouldReceive('select')-&amp;gt;once()-&amp;gt;andReturn( $db );
        $db-&amp;gt;shouldReceive('where')-&amp;gt;once()-&amp;gt;andReturn( $db );
        $db-&amp;gt;shouldReceive('limit')-&amp;gt;once()-&amp;gt;andReturn( $db );
        $db-&amp;gt;shouldReceive('get')-&amp;gt;once()-&amp;gt;andReturn( $result );

        return $db;
    }

}
&lt;/pre&gt;&lt;p&gt;I&amp;#39;ve added something new to this unit test: Mockery. Mockery lets you &amp;quot;mock&amp;quot; (fake) PHP objects. In this case, we&amp;#39;re mocking the database connection. With our mock, we can skip over testing a database connection and simply test our model.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Want to &lt;a
href="http://net.tutsplus.com/tutorials/php/mockery-a-better-way/"&gt;learn more about Mockery&lt;/a&gt;?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;In this case, we&amp;#39;re mocking a SQL connection. We&amp;#39;re telling the mock object to expect to have the &lt;code&gt;select&lt;/code&gt;, &lt;code&gt;where&lt;/code&gt;, &lt;code&gt;limit&lt;/code&gt; and &lt;code&gt;get&lt;/code&gt; methods called on it. I am returning the Mock, itself, to mirror how the SQL connection object returns itself (&lt;code&gt;$this&lt;/code&gt;), thus making its method calls &amp;quot;chainable&amp;quot;. Note that, for the &lt;code&gt;get&lt;/code&gt; method, I return the database call result &amp;#8211; a &lt;code&gt;stdClass&lt;/code&gt; object with the user data populated.&lt;/p&gt;&lt;p&gt;This solves a few problems:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;We&amp;#39;re testing only our model class. We&amp;#39;re not also testing a database connection.&lt;/li&gt;&lt;li&gt;We&amp;#39;re able to control the inputs and outputs of the mock database connection, and, therefore, can reliably test against the result of the database call. I know I&amp;#39;ll get a user ID of &amp;quot;1&amp;quot; as a result of the mocked database call.&lt;/li&gt;&lt;li&gt;We don&amp;#39;t need to bootstrap our application or have any configuration or database present to test.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;We can still do much better. Here&amp;#39;s where it gets interesting.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Interfaces&lt;/h2&gt;&lt;p&gt;To improve this further, we could define and implement an interface. Consider the following code.&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;
interface UserRepositoryInterface {
    public function getUser($user_id);
}

class MysqlUserRepository implements UserRepositoryInterface {

    protected $_db;

    public function __construct($db_conn)
    {
        $this-&amp;gt;_db = $db_conn;
    }

    public function getUser($user_id)
    {
        $user = $this-&amp;gt;_db-&amp;gt;select('user')
                    -&amp;gt;where('id', $user_id)
                    -&amp;gt;limit(1)
                    -&amp;gt;get();

        if ( $user-&amp;gt;num_results() &amp;gt; 0 )
        {
            return $user-&amp;gt;row();
        }

        return false;
    }

}

class User {

    protected $userStore;

    public function __construct(UserRepositoryInterface $user)
    {
        $this-&amp;gt;userStore = $user;
    }

    public function getUser($user_id)
    {
        return $this-&amp;gt;userStore-&amp;gt;getUser($user_id);
    }

}
&lt;/pre&gt;&lt;p&gt;There&amp;#39;s a few things happening here.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;First, we define an interface for our user &lt;em&gt;data source&lt;/em&gt;. This defines the &lt;code&gt;addUser()&lt;/code&gt; method.&lt;/li&gt;&lt;li&gt;Next, we implement that interface. In this case, we create a MySQL implementation. We accept a database connection object, and use it to grab a user from the database.&lt;/li&gt;&lt;li&gt;Lastly, we enforce the use of a class implementing the &lt;code&gt;UserInterface&lt;/code&gt; in our &lt;code&gt;User&lt;/code&gt; model. This guarantees that the data source will always have a &lt;code&gt;getUser()&lt;/code&gt; method available, no matter which data source is used to implement &lt;code&gt;UserInterface&lt;/code&gt;.&lt;/li&gt;&lt;/ol&gt;&lt;blockquote&gt;&lt;p&gt;Note that our &lt;code&gt;User&lt;/code&gt; object type-hints &lt;code&gt;UserInterface&lt;/code&gt; in its constructor. This means that a class implementing &lt;code&gt;UserInterface&lt;/code&gt; MUST be passed into the &lt;code&gt;User&lt;/code&gt; object. This is a guarantee we are relying on &amp;#8211; we need the &lt;code&gt;getUser&lt;/code&gt; method to always be available.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;What is the result of this?&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Our code is now &lt;em&gt;fully&lt;/em&gt; testable. For the &lt;code&gt;User&lt;/code&gt; class, we can easily mock the data source. (Testing the implementations of the datasource would be the job of a separate unit test).&lt;/li&gt;&lt;li&gt;Our code is &lt;em&gt;much&lt;/em&gt; more maintainable. We can switch out different data sources without having to change code throughout our application.&lt;/li&gt;&lt;li&gt;We can create &lt;em&gt;ANY&lt;/em&gt; data source. ArrayUser, MongoDbUser, CouchDbUser, MemoryUser, etc.&lt;/li&gt;&lt;li&gt;We can easily pass any data source to our &lt;code&gt;User&lt;/code&gt; object if we need to.  If you decide to ditch SQL, you can just create a different implementation (for instance, &lt;code&gt;MongoDbUser&lt;/code&gt;) and pass that into your &lt;code&gt;User&lt;/code&gt; model.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We&amp;#39;ve simplified our unit test, as well!&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;
&amp;lt;?php

use Mockery as m;
use Fideloper\User;

class ThirdUserTest extends PHPUnit_Framework_TestCase {

    public function testGetCurrentUserMock()
    {
        $userRepo = $this-&amp;gt;_mockUserRepo();

        $user = new User( $userRepo );

        $result = $user-&amp;gt;getUser( 1 );

        $expected = new StdClass();
        $expected-&amp;gt;id = 1;
        $expected-&amp;gt;username = 'fideloper';

        $this-&amp;gt;assertEquals( $result-&amp;gt;id, $expected-&amp;gt;id, 'User ID set correctly' );
        $this-&amp;gt;assertEquals( $result-&amp;gt;username, $expected-&amp;gt;username, 'Username set correctly' );
    }

    protected function _mockUserRepo()
    {
        // Mock expected result
        $result = new StdClass();
        $result-&amp;gt;id = 1;
        $result-&amp;gt;username = 'fideloper';

        // Mock any user repository
        $userRepo = m::mock('Fideloper\Third\Repository\UserRepositoryInterface');
        $userRepo-&amp;gt;shouldReceive('getUser')-&amp;gt;once()-&amp;gt;andReturn( $result );

        return $userRepo;
    }

}
&lt;/pre&gt;&lt;p&gt;We&amp;#39;ve taken the work of mocking a database connection out completely. Instead, we simply mock the data source, and tell it what to do when &lt;code&gt;getUser&lt;/code&gt; is called.&lt;/p&gt;&lt;p&gt;But, we can still do better!&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Containers&lt;/h2&gt;&lt;p&gt;Consider the usage of our current code:&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;
// In some controller
$user = new User( new MysqlUser( App:db-&amp;gt;getConnection(&amp;quot;mysql&amp;quot;) ) );
$user-&amp;gt;id = App::session(&amp;quot;user-&amp;gt;id&amp;quot;);

$currentUser = $user-&amp;gt;getUser($user_id);
&lt;/pre&gt;&lt;p&gt;Our final step will be to introduce &lt;em&gt;containers&lt;/em&gt;. In the above code, we need to create and use a bunch of objects just to get our current user. This code might be littered across your application. If you need to switch from MySQL to MongoDB, you&amp;#39;ll &lt;em&gt;still&lt;/em&gt; need to edit every place where the above code appears. That&amp;#39;s hardly DRY. &lt;a
href="http://pimple.sensiolabs.org/"&gt;Containers&lt;/a&gt; can fix this.&lt;/p&gt;&lt;p&gt;A container simply &amp;quot;contains&amp;quot; an object or functionality. It&amp;#39;s similar to a registry in your application. We can use a container to automatically instantiate a new &lt;code&gt;User&lt;/code&gt; object with all needed dependencies. Below, I use &lt;a
href="http://pimple.sensiolabs.org/"&gt;Pimple&lt;/a&gt;, a popular container class.&lt;/p&gt;&lt;pre class="brush: php; title: ; notranslate"&gt;
// Somewhere in a configuration file
$container = new Pimple();
$container[&amp;quot;user&amp;quot;] = function() {
    return new User( new MysqlUser( App:db-&amp;gt;getConnection('mysql') ) );
}

// Now, in all of our controllers, we can simply write:
$currentUser = $container['user']-&amp;gt;getUser( App::session('user_id') );
&lt;/pre&gt;&lt;p&gt;I&amp;#39;ve moved the creation of the &lt;code&gt;User&lt;/code&gt; model into one location in the application configuration. As a result:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;We&amp;#39;ve kept our code DRY. The &lt;code&gt;User&lt;/code&gt; object and the data store of choice is defined in one location in our application.&lt;/li&gt;&lt;li&gt;We can switch out our &lt;code&gt;User&lt;/code&gt; model from using MySQL to any other data source in &lt;strong&gt;ONE&lt;/strong&gt; location. This is vastly more maintainable.&lt;/li&gt;&lt;/ol&gt;&lt;hr
/&gt;&lt;h2&gt;Final Thoughts&lt;/h2&gt;&lt;p&gt;Over the course of this tutorial, we accomplished the following:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Kept our code DRY and reusable&lt;/li&gt;&lt;li&gt;Created maintainable code &amp;#8211; We can switch out data sources for our objects in one location for the entire application if needed&lt;/li&gt;&lt;li&gt;Made our code testable &amp;#8211; We can mock objects easily without relying on bootstrapping our application or creating a test database&lt;/li&gt;&lt;li&gt;Learned about using Dependency Injection and Interfaces, in order to enable creating testable and maintainable code&lt;/li&gt;&lt;li&gt;Saw how containers can aid in making our application more maintainable&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;I&amp;#39;m sure you&amp;#39;ve noticed that we&amp;#39;ve added much more code in the name of maintainability and testability. A strong argument can be made against this implementation: we&amp;#39;re increasing complexity. Indeed, this requires a deeper knowledge of code, both for the main author and for collaborators of a project.&lt;/p&gt;&lt;p&gt;However, the cost of explanation and understanding is far out-weighed by the extra overall &lt;em&gt;decrease&lt;/em&gt; in technical debt.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The code is vastly more maintainable, making changes possible in one location, rather than several.&lt;/li&gt;&lt;li&gt;Being able to unit test (quickly) will reduce bugs in code by a large margin &amp;#8211; especially in long-term or community-driven (open-source) projects.&lt;/li&gt;&lt;li&gt;Doing the extra-work up front &lt;em&gt;will&lt;/em&gt; save time and headache later.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Resources&lt;/h3&gt;&lt;p&gt;You may include &lt;strong&gt;Mockery&lt;/strong&gt; and &lt;strong&gt;PHPUnit&lt;/strong&gt; into your application easily using &lt;a
href="http://getcomposer.org/"&gt;Composer&lt;/a&gt;. Add these to your &amp;quot;require-dev&amp;quot; section in your &lt;code&gt;composer.json&lt;/code&gt; file:&lt;/p&gt;&lt;pre class="brush: jscript; title: ; notranslate"&gt;
&amp;quot;require-dev&amp;quot;: {
    &amp;quot;mockery/mockery&amp;quot;: &amp;quot;0.8.*&amp;quot;,
    &amp;quot;phpunit/phpunit&amp;quot;: &amp;quot;3.7.*&amp;quot;
}
&lt;/pre&gt;&lt;p&gt;You can then install your Composer-based dependencies with the &amp;quot;dev&amp;quot; requirements:&lt;/p&gt;&lt;pre class="brush: bash; title: ; notranslate"&gt;
$ php composer.phar install --dev
&lt;/pre&gt;&lt;p&gt;Learn more about Mockery, Composer and PHPUnit here on Nettuts+.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a
href="http://net.tutsplus.com/tutorials/php/mockery-a-better-way/"&gt;Mockery: A Better Way&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="http://net.tutsplus.com/tutorials/php/easy-package-management-with-composer/"&gt;Easy Package Management With Composer&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="http://net.tutsplus.com/sessions/test-driven-php/"&gt;Test-Driven PHP&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For PHP, consider using Laravel 4, as it makes exceptional use of &lt;a
href="http://four.laravel.com/docs/ioc"&gt;containers&lt;/a&gt; and other concepts written about here.&lt;/p&gt;&lt;p&gt;Thanks for reading!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=l6VzPp300us:W9HQQhbY1HM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=l6VzPp300us:W9HQQhbY1HM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=l6VzPp300us:W9HQQhbY1HM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=l6VzPp300us:W9HQQhbY1HM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=l6VzPp300us:W9HQQhbY1HM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=l6VzPp300us:W9HQQhbY1HM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=l6VzPp300us:W9HQQhbY1HM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=l6VzPp300us:W9HQQhbY1HM:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nettuts/~4/l6VzPp300us" height="1" width="1"/&gt;</description> <wfw:commentRss>http://net.tutsplus.com/tutorials/php/how-to-write-testable-and-maintainable-code-in-php/feed/</wfw:commentRss> <slash:comments>32</slash:comments> <feedburner:origLink>http://net.tutsplus.com/tutorials/php/how-to-write-testable-and-maintainable-code-in-php/</feedburner:origLink></item> <item><title>Real Time Chat With NodeJS, Socket.io and ExpressJS</title><link>http://feedproxy.google.com/~r/nettuts/~3/eOVTqZbxzsA/</link> <comments>http://net.tutsplus.com/tutorials/javascript-ajax/real-time-chat-with-nodejs-socket-io-and-expressjs/#comments</comments> <pubDate>Tue, 14 May 2013 17:57:14 +0000</pubDate> <dc:creator>Krasimir Tsonev</dc:creator> <category><![CDATA[JavaScript & AJAX]]></category> <category><![CDATA[expressjs]]></category> <category><![CDATA[nodejs]]></category> <category><![CDATA[socket.io]]></category> <guid isPermaLink="false">http://net.tutsplus.com/?p=31708</guid> <description>&lt;a
href='http://rss.buysellads.com/click.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31708&amp;c=1347185230' target='_blank'&gt;&lt;img
src='http://rss.buysellads.com/img.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31708&amp;c=1347185230' border='0' alt='' /&gt;&lt;/a&gt;&lt;p&gt;&lt;a
href="http://nodejs.org/"&gt;NodeJS&lt;/a&gt; gives me the ability to write back-end code in one of my favorite languages: JavaScript. It&amp;#39;s the perfect technology for building real time applications. In this tutorial, I&amp;#39;ll show you how to build a web chat application, using ExpressJS and &lt;a
href="http://socket.io/"&gt;Socket.io&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;span
id="more-31708"&gt;&lt;/span&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Setup Environment&lt;/h2&gt;&lt;p&gt;Of course, the first thing to do is get &lt;a
href="http://nodejs.org/"&gt;NodeJS&lt;/a&gt; installed on your system. If you are a Windows or Mac user, you can visit &lt;a
href="http://nodejs.org/download/"&gt;nodejs.org&lt;/a&gt; and download the installer. If you instead prefer Linux, I&amp;#39;d suggest that you refer to this &lt;a
href="https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager"&gt;link&lt;/a&gt;. Although I won&amp;#8217;t go into further details on this, if you encounter any installation issues, I&amp;#8217;m happy to help; just leave a comment below this post.&lt;/p&gt;&lt;p&gt;Once you have NodeJS installed, you&amp;#8217;re ready to setup the needed instruments.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;a
href="http://expressjs.com/"&gt;ExpressJS&lt;/a&gt; &amp;#8211; this will manage the server and the response to the user&lt;/li&gt;&lt;li&gt;&lt;a
href="http://jade-lang.com/"&gt;Jade&lt;/a&gt; &amp;#8211; template engine&lt;/li&gt;&lt;li&gt;&lt;a
href="http://socket.io/"&gt;Socket.io&lt;/a&gt; &amp;#8211; allows for real time communication between the front-end and back-end&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Continuing on, within an empty directory, create a &lt;em&gt;package.json&lt;/em&gt; file with the following content.&lt;/p&gt;&lt;pre class="brush: jscript; title: ; notranslate"&gt;{
    &amp;quot;name&amp;quot;: &amp;quot;RealTimeWebChat&amp;quot;,
    &amp;quot;version&amp;quot;: &amp;quot;0.0.0&amp;quot;,
    &amp;quot;description&amp;quot;: &amp;quot;Real time web chat&amp;quot;,
    &amp;quot;dependencies&amp;quot;: {
        &amp;quot;socket.io&amp;quot;: &amp;quot;latest&amp;quot;,
        &amp;quot;express&amp;quot;: &amp;quot;latest&amp;quot;,
        &amp;quot;jade&amp;quot;: &amp;quot;latest&amp;quot;
    },
    &amp;quot;author&amp;quot;: &amp;quot;developer&amp;quot;
}
&lt;/pre&gt;&lt;p&gt;By using the console (under Windows &amp;#8211; command prompt), navigate to your folder and execute:&lt;/p&gt;&lt;pre class="brush: bash; title: ; notranslate"&gt;npm install
&lt;/pre&gt;&lt;p&gt;Within a few seconds, you&amp;#8217;ll have all the necessary dependencies downloaded to the &lt;em&gt;node_modules&lt;/em&gt; directory.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Developing the Backend&lt;/h2&gt;&lt;p&gt;Let&amp;#8217;s begin with a simple server, which will deliver the application&amp;#39;s HTML page, and then continue with the more interesting bits: the real time communication. Create an &lt;em&gt;index.js&lt;/em&gt; file with the following core &lt;a
href="http://expressjs.com/"&gt;expressjs&lt;/a&gt; code:&lt;/p&gt;&lt;pre class="brush: jscript; title: ; notranslate"&gt;var express = require(&amp;quot;express&amp;quot;);
var app = express();
var port = 3700;

app.get(&amp;quot;/&amp;quot;, function(req, res){
    res.send(&amp;quot;It works!&amp;quot;);
});

app.listen(port);
console.log(&amp;quot;Listening on port &amp;quot; + port);
&lt;/pre&gt;&lt;p&gt;Above, we&amp;#8217;ve created an application and defined its port. Next, we registered a route, which, in this case, is a simple GET request without any parameters. For now, the route&amp;#8217;s handler simply sends some text to the client. Finally, of course, at the bottom, we run the server. To initialize the application, from the console, execute:&lt;/p&gt;&lt;pre class="brush: bash; title: ; notranslate"&gt;node index.js
&lt;/pre&gt;&lt;p&gt;The server is running, so you should be able to open &lt;em&gt;http://127.0.0.1:3700/&lt;/em&gt; and see:&lt;/p&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;It works!
&lt;/pre&gt;&lt;p&gt;Now, instead of &lt;em&gt;&amp;quot;It works&amp;quot;&lt;/em&gt; we should serve HTML. Instead of pure HTML, it can be beneficial  to use a template engine. &lt;a
href="http://jade-lang.com/"&gt;Jade&lt;/a&gt; is an excellent choice, which has good integration with ExpressJS. This is what I typically use in my own projects. Create a directory, called &lt;em&gt;tpl&lt;/em&gt;, and put the following &lt;em&gt;page.jade&lt;/em&gt; file within it:&lt;/p&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;!!!
html
    head
        title= &amp;quot;Real time web chat&amp;quot;
    body
        #content(style='width: 500px; height: 300px; margin: 0 0 20px 0; border: solid 1px #999; overflow-y: scroll;')
        .controls
            input.field(style='width:350px;')
            input.send(type='button', value='send')
&lt;/pre&gt;&lt;p&gt;The Jade&amp;#39;s syntax is not so complex, but, for a full guide, I suggest that you refer to &lt;a
href="http://jade-lang.com/"&gt;jade-lang.com&lt;/a&gt;. In order to use Jade with ExpressJS, we require the following settings.&lt;/p&gt;&lt;pre class="brush: jscript; title: ; notranslate"&gt;app.set('views', __dirname + '/tpl');
app.set('view engine', &amp;quot;jade&amp;quot;);
app.engine('jade', require('jade').__express);
app.get(&amp;quot;/&amp;quot;, function(req, res){
    res.render(&amp;quot;page&amp;quot;);
});
&lt;/pre&gt;&lt;p&gt;This code informs Express where your template files are, and which template engine to use. It all specifies the function that will process the template&amp;#39;s code. Once everything is setup, we can use the &lt;code&gt;.render&lt;/code&gt; method of the &lt;code&gt;response&lt;/code&gt; object, and simply send our Jade code to the user.&lt;/p&gt;&lt;p&gt; The output isn&amp;#8217;t special at this point; nothing more than a &lt;code&gt;div&lt;/code&gt; element (the one with id &lt;code&gt;content&lt;/code&gt;), which will be used as a holder for the chat messages and two controls (input field and button), which we will use to send the message.&lt;/p&gt;&lt;p&gt;Because we will use an external JavaScript file that will hold the front-end logic, we need to inform ExpressJS where to look for such resources. Create an empty directory, &lt;code&gt;public&lt;/code&gt;, and add the following line before the call to the &lt;code&gt;.listen&lt;/code&gt; method.&lt;/p&gt;&lt;pre class="brush: jscript; title: ; notranslate"&gt;app.use(express.static(__dirname + '/public'));
&lt;/pre&gt;&lt;p&gt;So far so good; we have a server that successfully responds to GET requests. Now, it&amp;#8217;s time to add &lt;em&gt;Socket.io&lt;/em&gt; integration. Change this line:&lt;/p&gt;&lt;pre class="brush: jscript; title: ; notranslate"&gt;app.listen(port);
&lt;/pre&gt;&lt;p&gt;to:&lt;/p&gt;&lt;pre class="brush: jscript; title: ; notranslate"&gt;var io = require('socket.io').listen(app.listen(port));
&lt;/pre&gt;&lt;p&gt;Above, we passed the ExpressJS server to Socket.io. In effect, our real time communication will still happen on the same port.&lt;/p&gt;&lt;p&gt;Moving forward, we need to write the code that will receive a message from the client, and send it to all the others. Every Socket.io application begins with a &lt;code&gt;connection&lt;/code&gt; handler. We should have one:&lt;/p&gt;&lt;pre class="brush: jscript; title: ; notranslate"&gt;io.sockets.on('connection', function (socket) {
    socket.emit('message', { message: 'welcome to the chat' });
    socket.on('send', function (data) {
        io.sockets.emit('message', data);
    });
});
&lt;/pre&gt;&lt;p&gt;The object, &lt;code&gt;socket&lt;/code&gt;, which is passed to your handler, is actually the socket of the client. Think about it as a junction between your server and the user&amp;#39;s browser. Upon a successful connection, we send a &lt;code&gt;welcome&lt;/code&gt; type of message, and, of course, bind another handler that will be used as a receiver. As a result, the client should emit a message with the name, &lt;code&gt;send&lt;/code&gt;, which we will catch. Following that, we  simply forward the data sent by the user to all other sockets with &lt;code&gt;io.sockets.emit&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;With the code above, our back-end is ready to receive and send messages to the clients. Let&amp;#39;s add some front-end code.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Developing the Front-end&lt;/h2&gt;&lt;p&gt;Create &lt;code&gt;chat.js&lt;/code&gt;, and place it within the &lt;code&gt;public&lt;/code&gt; directory of your application. Paste the following code:&lt;/p&gt;&lt;pre class="brush: jscript; title: ; notranslate"&gt;window.onload = function() {

    var messages = [];
    var socket = io.connect('http://localhost:3700');
    var field = document.getElementById(&amp;quot;field&amp;quot;);
    var sendButton = document.getElementById(&amp;quot;send&amp;quot;);
    var content = document.getElementById(&amp;quot;content&amp;quot;);

    socket.on('message', function (data) {
        if(data.message) {
            messages.push(data.message);
            var html = '';
            for(var i=0; i&amp;lt;messages.length; i++) {
                html += messages[i] + '&amp;lt;br /&amp;gt;';
            }
            content.innerHTML = html;
        } else {
            console.log(&amp;quot;There is a problem:&amp;quot;, data);
        }
    });

    sendButton.onclick = function() {
        var text = field.value;
        socket.emit('send', { message: text });
    };

}
&lt;/pre&gt;&lt;p&gt;Our logic is wrapped in a &lt;code&gt;.onload&lt;/code&gt; handler just to ensure that all the markup and external JavaScript is fully loaded. In the next few lines, we create an array, which will store all the messages, a &lt;code&gt;socket&lt;/code&gt; object, and few shortcuts to our DOM elements. Again, similar to the back-end, we bind a function, which will react to the socket&amp;#39;s activity. In our case, this is an event, named &lt;code&gt;message&lt;/code&gt;. When such an event occurs, we expect to receive an object, &lt;em&gt;data&lt;/em&gt;, with the property, &lt;code&gt;message&lt;/code&gt;. Add that message to our storage and update the &lt;code&gt;content&lt;/code&gt; &lt;code&gt;div&lt;/code&gt;. We&amp;#8217;ve also included the logic for sending the message. It&amp;#8217;s quite simple, simply emitting a message with the name, &lt;em&gt;send&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;If you open &lt;em&gt;http://localhost:3700&lt;/em&gt;, you will encounter some errors popup. That&amp;#39;s because we need to update &lt;code&gt;page.jade&lt;/code&gt; to contain the necessary JavaScript files.&lt;/p&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;head
    title= &amp;quot;Real time web chat&amp;quot;
    script(src='/chat.js')
    script(src='/socket.io/socket.io.js')
&lt;/pre&gt;&lt;p&gt;Notice that Socket.io manages the delivery of &lt;em&gt;socket.io.js&lt;/em&gt;. You don&amp;#39;t have to worry about manually downloading this file.&lt;/p&gt;&lt;p&gt;We can again run our server with &lt;code&gt;node index.js&lt;/code&gt; in the console and open &lt;em&gt;http://localhost:3700&lt;/em&gt;. You should see the welcome message. Of course, if you send something, it should be shown in the content&amp;#39;s &lt;code&gt;div&lt;/code&gt;. If you want to be sure that it works, open a new tab (or, better, a new browser) and load the application. The great thing about Socket.io is that it works even if you stop the NodeJS server. The front-end will continue to work. Once the server is booted up again, your chat will be fine too.&lt;/p&gt;&lt;p&gt;In its current state, our chat is not perfect, and requires some improvements.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Improvements&lt;/h2&gt;&lt;p&gt;The first change that we need to make is to the identity of the messages. Currently, it&amp;#39;s not clear which messages is sent by whom. The good thing is that we don&amp;#39;t have to update our NodeJS code to achieve this. That&amp;#39;s because the server simply forwards the &lt;code&gt;data&lt;/code&gt; object. So, we need to add a new property there, and read it later. Before making corrections to &lt;code&gt;chat.js&lt;/code&gt;, let&amp;#8217;s add a new &lt;code&gt;input&lt;/code&gt; field, where the user may add his/her name. Within &lt;code&gt;page.jade&lt;/code&gt;, change the &lt;code&gt;controls&lt;/code&gt; &lt;code&gt;div&lt;/code&gt;:&lt;/p&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;.controls
    | Name: 
    input#name(style='width:350px;')
    br
    input#field(style='width:350px;')
    input#send(type='button', value='send')
&lt;/pre&gt;&lt;p&gt;Next, in &lt;em&gt;code.js&lt;/em&gt;:&lt;/p&gt;&lt;pre class="brush: jscript; title: ; notranslate"&gt;window.onload = function() {

    var messages = [];
    var socket = io.connect('http://localhost:3700');
    var field = document.getElementById(&amp;quot;field&amp;quot;);
    var sendButton = document.getElementById(&amp;quot;send&amp;quot;);
    var content = document.getElementById(&amp;quot;content&amp;quot;);
    var name = document.getElementById(&amp;quot;name&amp;quot;);

    socket.on('message', function (data) {
        if(data.message) {
            messages.push(data);
            var html = '';
            for(var i=0; i&amp;lt;messages.length; i++) {
                html += '&amp;lt;b&amp;gt;' + (messages[i].username ? messages[i].username : 'Server') + ': &amp;lt;/b&amp;gt;';
                html += messages[i].message + '&amp;lt;br /&amp;gt;';
            }
            content.innerHTML = html;
        } else {
            console.log(&amp;quot;There is a problem:&amp;quot;, data);
        }
    });

    sendButton.onclick = function() {
        if(name.value == &amp;quot;&amp;quot;) {
            alert(&amp;quot;Please type your name!&amp;quot;);
        } else {
            var text = field.value;
            socket.emit('send', { message: text, username: name.value });
        }
    };

}
&lt;/pre&gt;&lt;p&gt;To summarize the changes, we&amp;#8217;ve:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Added a new shortcut for the username&amp;#39;s &lt;code&gt;input&lt;/code&gt; field&lt;/li&gt;&lt;li&gt;Updated the presentation of the messages a bit&lt;/li&gt;&lt;li&gt;Appended a new &lt;code&gt;username&lt;/code&gt; property to the object, which is sent to the server&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;If the the number of messages becomes too high, the user will need to scroll the &lt;code&gt;div&lt;/code&gt;:&lt;/p&gt;&lt;pre class="brush: jscript; title: ; notranslate"&gt;content.innerHTML = html;
content.scrollTop = content.scrollHeight;
&lt;/pre&gt;&lt;p&gt;Keep in mind that the above solution will likely not work in IE7 and below, but that&amp;#8217;s okay: it&amp;#8217;s time for IE7 to fade away. However, if you want to ensure support, feel free to use jQuery:&lt;/p&gt;&lt;pre class="brush: jscript; title: ; notranslate"&gt;$(&amp;quot;#content&amp;quot;).scrollTop($(&amp;quot;#content&amp;quot;)[0].scrollHeight);
&lt;/pre&gt;&lt;p&gt;It would also be nice if the input field is cleared after sending the message:&lt;/p&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;socket.emit('send', { message: text, username: name.value });
field.value = &amp;quot;&amp;quot;;
&lt;/pre&gt;&lt;p&gt;The final boring problem is the clicking of the &lt;em&gt;send&lt;/em&gt; button each time. With a touch of jQuery, we can listen for when the user presses the &lt;code&gt;Enter&lt;/code&gt; key.&lt;/p&gt;&lt;pre class="brush: jscript; title: ; notranslate"&gt;$(document).ready(function() {
    $(&amp;quot;#field&amp;quot;).keyup(function(e) {
        if(e.keyCode == 13) {
            sendMessage();
        }
    });
});
&lt;/pre&gt;&lt;p&gt;The function, &lt;code&gt;sendMessage&lt;/code&gt;, could be registered, like so:&lt;/p&gt;&lt;pre class="brush: jscript; title: ; notranslate"&gt;sendButton.onclick = sendMessage = function() {
    ...
};
&lt;/pre&gt;&lt;p&gt;Please note that this isn&amp;#8217;t a best practice, as it is registered as a global function. But, for our little test here, it&amp;#8217;ll be fine.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;NodeJS is an extremely useful technology, and provides us with a great deal of power and joy, especially when considering the fact that we can write pure JavaScript. As you can see, with only a few lines of code, we managed to write a fully functional real time chat application. Pretty neat!&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt; Want to learn more about building web apps with ExpressJS? &lt;a
href="https://tutsplus.com/course/building-web-apps-in-node-and-express/"&gt;We&amp;#8217;ve got you covered!&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=eOVTqZbxzsA:iPYAPfL2ZpQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=eOVTqZbxzsA:iPYAPfL2ZpQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=eOVTqZbxzsA:iPYAPfL2ZpQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=eOVTqZbxzsA:iPYAPfL2ZpQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=eOVTqZbxzsA:iPYAPfL2ZpQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=eOVTqZbxzsA:iPYAPfL2ZpQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=eOVTqZbxzsA:iPYAPfL2ZpQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=eOVTqZbxzsA:iPYAPfL2ZpQ:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nettuts/~4/eOVTqZbxzsA" height="1" width="1"/&gt;</description> <wfw:commentRss>http://net.tutsplus.com/tutorials/javascript-ajax/real-time-chat-with-nodejs-socket-io-and-expressjs/feed/</wfw:commentRss> <slash:comments>27</slash:comments> <feedburner:origLink>http://net.tutsplus.com/tutorials/javascript-ajax/real-time-chat-with-nodejs-socket-io-and-expressjs/</feedburner:origLink></item> <item><title>Mass Assignment, Rails, and You</title><link>http://feedproxy.google.com/~r/nettuts/~3/XpoNYQDjTzU/</link> <comments>http://net.tutsplus.com/tutorials/ruby/mass-assignment-rails-and-you/#comments</comments> <pubDate>Mon, 13 May 2013 18:00:20 +0000</pubDate> <dc:creator>Arun Srinivasan</dc:creator> <category><![CDATA[Ruby]]></category> <category><![CDATA[rails]]></category> <category><![CDATA[tips]]></category> <guid isPermaLink="false">http://net.tutsplus.com/?p=31695</guid> <description>&lt;a
href='http://rss.buysellads.com/click.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31695&amp;c=1551671227' target='_blank'&gt;&lt;img
src='http://rss.buysellads.com/img.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31695&amp;c=1551671227' border='0' alt='' /&gt;&lt;/a&gt;&lt;p&gt;Early in 2012, a developer, named Egor Homakov, took advantage of a security hole at &lt;a
href="github"&gt;Github&lt;/a&gt; (a Rails app) to gain commit access to the &lt;a
href="https://github.com/rails/rails"&gt;Rails&lt;/a&gt; project.&lt;/p&gt;&lt;p&gt;His intent was mostly to point out a common security issue with many Rails apps that results from a feature, known as mass assignment (and did so rather loudly). In this article, we&amp;#39;ll review what mass assignment is, how it can be a problem, and what you can do about it in your own applications.&lt;/p&gt;&lt;p&gt;&lt;span
id="more-31695"&gt;&lt;/span&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;What is Mass Assignment?&lt;/h2&gt;&lt;p&gt;To begin, let&amp;#39;s first take a look at what mass assignment means, and why it exists. By way of an example, imagine that we have the following &lt;code&gt;User&lt;/code&gt; class in our application:&lt;/p&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;# Assume the following fields: [:id, :first, :last, :email]
class User &amp;lt; ActiveRecord::Base
end
&lt;/pre&gt;&lt;p&gt;Mass assignment allows us to set a bunch of attributes at once:&lt;/p&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;attrs = {:first =&amp;gt; &amp;quot;John&amp;quot;, :last =&amp;gt; &amp;quot;Doe&amp;quot;, :email =&amp;gt; &amp;quot;john.doe@example.com&amp;quot;}
user = User.new(attrs)
user.first #=&amp;gt; &amp;quot;John&amp;quot;
user.last  #=&amp;gt; &amp;quot;Doe&amp;quot;
user.email #=&amp;gt; &amp;quot;john.doe@example.com&amp;quot;
&lt;/pre&gt;&lt;p&gt;Without the convenience of mass assignment, we&amp;#39;d have to write an assignment statement for each attribute to achieve the same result. Here&amp;#8217;s an example:&lt;/p&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;attrs = {:first =&amp;gt; &amp;quot;John&amp;quot;, :last =&amp;gt; &amp;quot;Doe&amp;quot;, :email =&amp;gt; &amp;quot;john.doe@example.com&amp;quot;}
user = User.new
user.first = attrs[:first]
user.last  = attrs[:last]
user.email = attrs[:email]
user.first #=&amp;gt; &amp;quot;John&amp;quot;
user.last  #=&amp;gt; &amp;quot;Doe&amp;quot;
user.email #=&amp;gt; &amp;quot;john.doe@example.com&amp;quot;
&lt;/pre&gt;&lt;p&gt;Obviously, this can get tedious and painful; so we bow at the feet of laziness and say, yes yes, mass assignment is a good thing.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;The (Potential) Problem With Mass Assignment&lt;/h2&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; One problem with sharp tools is that you can cut yourself with them.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;But wait! One problem with sharp tools is that you can cut yourself with them. Mass assignment is no exception to this rule.&lt;/p&gt;&lt;p&gt;Suppose now that our little imaginary application has acquired the ability to fire missiles. As we don&amp;#39;t want the world to turn to ash, we add a boolean permission field to the &lt;code&gt;User&lt;/code&gt; model to decide who can fire missiles.&lt;/p&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;class AddCanFireMissilesFlagToUsers &amp;lt; ActiveRecord::Migration
  def change
    add_column :users, :can_fire_missiles, :boolean, :default =&amp;gt; false
  end
end
&lt;/pre&gt;&lt;p&gt;Let&amp;#39;s also assume that we have a way for users to edit their contact information: this might be a form somewhere that is accessible to the user with text fields for the user&amp;#39;s first name, last name, and email address.&lt;/p&gt;&lt;p&gt;Our friend John Doe decides to change his name and update his email account. When he submits the form, the browser will issue a request similar to the following:&lt;/p&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;PUT http://missileapp.com/users/42?user[first]=NewJohn&amp;amp;user[email]=john.doe@newemail.com
&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;update&lt;/code&gt; action within the &lt;code&gt;UsersController&lt;/code&gt; might look something like:&lt;/p&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;def update
  user = User.find(params[:id])
  if user.update_attributes(params[:user]) # Mass assignment!
    redirect_to home_path
  else
    render :edit
  end
end
&lt;/pre&gt;&lt;p&gt;Given our example request, the &lt;code&gt;params&lt;/code&gt; hash will look similar to:&lt;/p&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;{:id =&amp;gt; 42, :user =&amp;gt; {:first =&amp;gt; &amp;quot;NewJohn&amp;quot;, :email =&amp;gt; &amp;quot;john.doe@newemail.com&amp;quot;}
# :id - parsed by the router
# :user - parsed from the incoming querystring
&lt;/pre&gt;&lt;p&gt;Now let&amp;#39;s say that NewJohn gets a little sneaky. You don&amp;#39;t necessarily need a browser to issue an HTTP request, so he writes a script that issues the following request:&lt;/p&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;PUT http://missileapp.com/users/42?user[can_fire_missiles]=true
&lt;/pre&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; Fields, like &lt;code&gt;:admin&lt;/code&gt;, &lt;code&gt;:owner&lt;/code&gt;, and &lt;code&gt;:public_key&lt;/code&gt;, are quite easily guessable.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;When this request hits our &lt;code&gt;update&lt;/code&gt; action, the &lt;code&gt;update_attributes&lt;/code&gt; call will see &lt;code&gt;{:can_fire_missiles =&gt; true}&lt;/code&gt;, and give NewJohn the ability to fire missiles! Woe has become us.&lt;/p&gt;&lt;p&gt;This is exactly how Egor Homakov gave himself commit access to the Rails project. Because Rails is so convention-heavy, fields like &lt;code&gt;:admin&lt;/code&gt;, &lt;code&gt;:owner&lt;/code&gt;, and &lt;code&gt;:public_key&lt;/code&gt; are quite easily guessable. Further, if there aren&amp;#39;t protections in place, you can gain access to things that you&amp;#39;re not supposed to be able to touch.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;How to Deal With Mass Assignment&lt;/h2&gt;&lt;p&gt;So how do we protect ourselves from wanton mass assignment? How do we prevent the NewJohns of the world from firing our missiles with reckless abandon?&lt;/p&gt;&lt;p&gt;Luckily, Rails provides a couple tools to manage the issue: &lt;code&gt;attr_protected&lt;/code&gt; and &lt;code&gt;attr_accessible&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;&lt;code&gt;attr_protected&lt;/code&gt;: The BlackList&lt;/h3&gt;&lt;p&gt;Using &lt;code&gt;attr_protected&lt;/code&gt;, you can specify which fields may never be &lt;em&gt;mass-ly&lt;/em&gt; assignable:&lt;/p&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;class User &amp;lt; ActiveRecord::Base
  attr_protected :can_fire_missiles
end
&lt;/pre&gt;&lt;p&gt;Now, any attempt to mass-assign the &lt;code&gt;can_fire_missiles&lt;/code&gt; attribute will fail.&lt;/p&gt;&lt;h3&gt;&lt;code&gt;attr_accessible&lt;/code&gt;: The WhiteList&lt;/h3&gt;&lt;p&gt;The problem with &lt;code&gt;attr_protected&lt;/code&gt; is that it&amp;#39;s too easy to forget to add a newly implemented field to the list.&lt;/p&gt;&lt;p&gt;This is where &lt;code&gt;attr_accessible&lt;/code&gt; comes in. As you might have guessed, it&amp;#39;s the opposite of &lt;code&gt;attr_protected&lt;/code&gt;: only list the attributes that you want to be mass-assignable.&lt;/p&gt;&lt;p&gt;As such, we can switch our &lt;code&gt;User&lt;/code&gt; class to this approach:&lt;/p&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;class User &amp;lt; ActiveRecord::Base
  attr_accessible :first, :last, :email
end
&lt;/pre&gt;&lt;p&gt;Here, we&amp;#39;re explicitly listing out what can be mass-assigned. Everything else will be disallowed. The advantage here is that if we, say, add an &lt;code&gt;admin&lt;/code&gt; flag to the &lt;code&gt;User&lt;/codE&gt; model, it will automatically be safe from mass-assignment.&lt;/p&gt;&lt;p&gt;As a general rule, you should prefer &lt;code&gt;attr_accessible&lt;/code&gt; to &lt;code&gt;attr_protected&lt;/code&gt;, as it helps you err on the side of caution.&lt;/p&gt;&lt;h3&gt;Mass Assignment Roles&lt;/h3&gt;&lt;p&gt;Rails 3.1 introduced the concept of mass-assignment &amp;quot;roles&amp;quot;. The idea is that you can specify different &lt;code&gt;attr_protected&lt;/code&gt; and &lt;code&gt;attr_accessible&lt;/code&gt; lists for different situations.&lt;/p&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;class User &amp;lt; ActiveRecord::Base
  attr_accessible :first, :last, :email             # :default role
  attr_accessible :can_fire_missiles, :as =&amp;gt; :admin # :admin role
end

user = User.new({:can_fire_missiles =&amp;gt; true}) # uses the :default role  
user.can_fire_missiles #=&amp;gt; false  

user2 = User.new({:can_fire_missiles =&amp;gt; true}, :as =&amp;gt; :admin)  
user.can_fire_missiles #=&amp;gt; true  
&lt;/pre&gt;&lt;h3&gt;Application-wide Configuration&lt;/h3&gt;&lt;p&gt;You can control mass assignment behavior in your application by editing the &lt;code&gt;config.active_record.whitelist_attributes&lt;/code&gt; setting within the &lt;code&gt;config/application.rb&lt;/code&gt; file.&lt;/p&gt;&lt;p&gt;If set to &lt;code&gt;false&lt;/code&gt;, mass assignment protection will only be activated for the models where you specify an &lt;code&gt;attr_protected&lt;/code&gt; or &lt;code&gt;attr_accessible&lt;/code&gt; list.&lt;/p&gt;&lt;p&gt;If set to &lt;code&gt;true&lt;/code&gt;, mass assignment will be impossible for all models unless they specify an &lt;code&gt;attr_protected&lt;/code&gt; or &lt;code&gt;attr_accessible&lt;/code&gt; list. Please note that this option is enabled by default from Rails 3.2.3 forward.&lt;/p&gt;&lt;h3&gt;Strictness&lt;/h3&gt;&lt;p&gt;Beginning with Rails 3.2, there is additionally a configuration option to control the strictness of mass assignment protection: &lt;code&gt;config.active_record.mass_assignment_sanitizer&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;If set to &lt;code&gt;:strict&lt;/code&gt;, it will raise an &lt;code&gt;ActiveModel::MassAssignmentSecurity::Error&lt;/code&gt; any time that your application attempts to mass-assign something it shouldn&amp;#39;t. You&amp;#39;ll need to handle these errors explicitly. As of v3.2, this option is set for you in the development and test environments (but not production), presumably to help you track down where mass-assignment issues might be.&lt;/p&gt;&lt;p&gt;If not set, it will handle mass-assignment protection silently - meaning that it will only set the attributes it&amp;#39;s supposed to, but won't raise an error.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Rails 4 Strong Parameters: A Different Approach&lt;/h2&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; Mass assignment security is really about handling untrusted input.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;The Homakov Incident initiated a conversation around mass assignment protection in the Rails community (and onward to other languages, as well); an interesting question was raised: does mass assignment security belong in the model layer?&lt;/p&gt;&lt;p&gt;Some applications have complex authorization requirements. Trying to handle all special cases in the model layer can begin to feel clunky and over-complicated, especially if you find yourself plastering &lt;code&gt;roles&lt;/code&gt; all over the place.&lt;/p&gt;&lt;p&gt;A key insight here is that mass assignment security is really about handling untrusted input. As a Rails application receives user input in the controller layer, developers began wondering whether it might be better to deal with the issue there instead of ActiveRecord models.&lt;/p&gt;&lt;p&gt;The result of this discussion is the &lt;a
href="strongparameters"&gt;Strong Parameters&lt;/a&gt; gem, available for use with Rails 3, and a default in the upcoming Rails 4 release.&lt;/p&gt;&lt;p&gt;Assuming that our missile application is bult on Rails 3, here&amp;#39;s how we might update it for use with the stong parameters gem:&lt;/p&gt;&lt;h4&gt;Add the gem&lt;/h4&gt;&lt;p&gt;Add the following line to the Gemfile:&lt;/p&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;gem strong_parameters
&lt;/pre&gt;&lt;h4&gt;Turn off model-based mass assignment protection&lt;/h4&gt;&lt;p&gt;Within &lt;code&gt;config/application.rb&lt;/code&gt;:&lt;/p&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;config.active_record.whitelist_attributes = false
&lt;/pre&gt;&lt;h4&gt;Tell the models about it&lt;/h4&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;class User &amp;lt; ActiveRecord::Base
  include ActiveModel::ForbiddenAttributesProtection
end
&lt;/pre&gt;&lt;h4&gt;Update the controllers&lt;/h4&gt;&lt;pre class="brush: ruby; title: ; notranslate"&gt;class UsersController &amp;lt; ApplicationController
  def update
    user = User.find(params[:id])
    if user.update_attributes(user_params) # see below
      redirect_to home_path
    else
      render :edit
    end
  end

  private

  # Require that :user be a key in the params Hash,
  # and only accept :first, :last, and :email attributes
  def user_params
    params.require(:user).permit(:first, :last, :email)
  end
end
&lt;/pre&gt;&lt;p&gt;Now, if you attempt something like &lt;code&gt;user.update_attributes(params)&lt;/code&gt;, you&amp;#39;ll get an error in your application. You must first call &lt;code&gt;permit&lt;/code&gt; on the &lt;code&gt;params&lt;/code&gt; hash with the keys that are allowed for a specific action.&lt;/p&gt;&lt;p&gt;The advantage to this approach is that you must be explicit about which input you accept at the point that you&amp;#39;re dealing with the input.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If this was a Rails 4 app, the controller code is all we&amp;#39;d need; the strong parameters functionality will be baked in by default. As a result, you won&amp;#39;t need the include in the model or the separate gem in the Gemfile.&lt;/p&gt;&lt;/blockquote&gt;&lt;hr
/&gt;&lt;h2&gt;Wrapping Up&lt;/h2&gt;&lt;p&gt;Mass assignment can be an incredibly useful feature when writing Rails code. In fact, it&amp;#39;s nearly impossible to write reasonable Rails code without it. Unfortunately, mindless mass assignment is also fraught with peril.&lt;/p&gt;&lt;p&gt;Hopefully, you&amp;#39;re now equipped with the necessary tools to navigate safely in the mass assignment waters. Here&amp;#39;s to fewer missiles!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=XpoNYQDjTzU:zFQKX_mHCTo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=XpoNYQDjTzU:zFQKX_mHCTo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=XpoNYQDjTzU:zFQKX_mHCTo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=XpoNYQDjTzU:zFQKX_mHCTo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=XpoNYQDjTzU:zFQKX_mHCTo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=XpoNYQDjTzU:zFQKX_mHCTo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=XpoNYQDjTzU:zFQKX_mHCTo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=XpoNYQDjTzU:zFQKX_mHCTo:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nettuts/~4/XpoNYQDjTzU" height="1" width="1"/&gt;</description> <wfw:commentRss>http://net.tutsplus.com/tutorials/ruby/mass-assignment-rails-and-you/feed/</wfw:commentRss> <slash:comments>5</slash:comments> <feedburner:origLink>http://net.tutsplus.com/tutorials/ruby/mass-assignment-rails-and-you/</feedburner:origLink></item> <item><title>Master Developers: Addy Osmani</title><link>http://feedproxy.google.com/~r/nettuts/~3/7hx3IvwhzZ0/</link> <comments>http://net.tutsplus.com/articles/interviews/master-developers-addy-osmani/#comments</comments> <pubDate>Fri, 10 May 2013 15:09:13 +0000</pubDate> <dc:creator>Rey Bango</dc:creator> <category><![CDATA[Interviews]]></category> <guid isPermaLink="false">http://net.tutsplus.com/?p=31661</guid> <description>&lt;a
href='http://rss.buysellads.com/click.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31661&amp;c=1750983368' target='_blank'&gt;&lt;img
src='http://rss.buysellads.com/img.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31661&amp;c=1750983368' border='0' alt='' /&gt;&lt;/a&gt;&lt;p&gt;A bright star in the JavaScript community, Addy Osmani has skyrocketed to prominence not only for his fabulous JavaScript articles and open source contributions but for also being one of the friendliest and approachable developers around.&lt;/p&gt;&lt;p&gt;His &lt;a
href="http://addyosmani.com/blog/"&gt;blog&lt;/a&gt; is a treasture trove of front-end knowledge and well-worth the visit. In this post, we&amp;#39;ll chat with Addy about how he got his feet wet in JS and bring up some tough topics relating to his work in developer relations at Google.&lt;/p&gt;&lt;p&gt;&lt;span
id="more-31661"&gt;&lt;/span&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;div
class="question"&gt;&lt;h4&gt;&lt;span&gt;Q&lt;/span&gt; You took to JavaScript like a fish to water. How&amp;#39;d you get so entrenched in the JS world?&lt;/h4&gt;&lt;/div&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; JavaScript was going to play a large role in making this possible.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I wrote some of my first JavaScript back when Netscape Navigator was the dominant browser. Dynamic front-end development was only slowly starting to becoming more popular at the time, but the idea of being able to write something with just HTML/CSS/JS and have it work everywhere was powerful. I got hooked on to that idea and have been ever since. Some of my first creations were little things you would laugh at today &amp;#8211; calculators, password generators, nothing too amazing.&lt;/p&gt;&lt;p&gt;As a language enthusiast, I liked that JavaScript was prototype-based and weakly typed, so I decided to continued learning it alongside other languages like C++. Back in the early 2000&amp;#39;s, I tried bridging the languages by writing a little interpreter on top of SpiderMonkey (Mozilla&amp;#39;s JavaScript engine), which let me write logic for my desktop apps in JS and define UI components using C++.  It was a silly idea, but I learned a lot about JavaScript engine internals in the process.&lt;/p&gt;&lt;p&gt;I spent a lot of time building small hobby sites, but when I was in my last year at high-school, I decided to really get stuck into the world of browser internals. I wrote a lightweight rendering engine, basic HTML 4.01/CSS 2.1 parsers and wrapped all of these parts into my own little browser. The project was a nightmare to get working reliably, in part due to how lax web developers were with standards-compliance in their pages &amp;#8211; it&amp;#39;s funny being on the other side of the fence now! The larger challenges were spec-compliance, rendering large tables and maintaining performance, whilst loading up video plugins (anyone remember good ol&amp;#39; ActiveX?).&lt;/p&gt;&lt;p&gt;I continued learning and using JavaScript as a freelance web developer while in college, slowly writing more complex sites and playing around with Dojo. It wasn&amp;#39;t, however, until I got an invitation to GMail in 2006 that it occurred to me that the browser was going to be the next platform for building rich applications. JavaScript was going to play a large role in making this possible and I decided to walk away from desktop app development permanently.&lt;/p&gt;&lt;p&gt;Since then, I&amp;#39;ve been trying to continue learning and where I can, push the front-end community forward through my writing and contributions to open-source. JavaScript is virtually everywhere today, and it&amp;#39;s one of the reasons why I love the language. If I want to teach one of my kids how to author JavaScript, I can just pop-open my browser DevTools and show them. No additional compilation steps needed &amp;#8211; there&amp;#39;s something really special about that.&lt;/p&gt;&lt;hr
/&gt;&lt;div
class="question"&gt;&lt;h4&gt;&lt;span&gt;Q&lt;/span&gt; You produce a LOT of content; I&amp;#39;m sure people are wondering how you do it. Can you share your secrets for not only generating this content, but actually understanding what you&amp;#39;re writing about?&lt;/h4&gt;&lt;/div&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; If you leap into any non-trivial topic with that mindset, it&amp;#39;s necessary to break it down into simple, more easily digestible steps&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;The secret is that I consider myself to be somewhat stupid. Really. If you leap into any non-trivial topic with that mindset, it&amp;#39;s necessary to break it down into simple, more easily digestible steps in order for it to make any semblance of sense.&lt;/p&gt;&lt;p&gt;It&amp;#39;s this perspective that I think makes my writing feel accessible &amp;#8211; I try to make sense of those concepts or tools that can initially feel quite daunting to the average developer. It&amp;#39;s important to be able to apply this to articles and especially documentation. So, keep it simple. This helps make articles more focused. How do I generate so much content whilst understanding the material?. Well, I make understanding a prerequisite.&lt;/p&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; First do it, then do it right, then do it better.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Einstein has this great quote: &amp;quot;If you can&amp;#39;t explain it simply, you don&amp;#39;t understand it well enough&amp;quot; and it&amp;#39;s true. You cannot teach about or claim a framework, tool or best practice, unless you&amp;#39;ve actually taken the time to use it yourself. Finding this time is easier in my current role, but back in my days as a 9-5 engineer, I would spend time over breakfast and lunch actively using what I would later write about on the weekend.&lt;/p&gt;&lt;p&gt;Finding time to get everything done is always a challenge. For the past few years, I have this mantra that I try to apply to every task &amp;#8211; &amp;#8220;&lt;me&gt;First do it, then do it right, then do it better&lt;/em&gt;&amp;#8221; &amp;#8211; it&amp;#39;s all about setting realistic goals for yourself and iterating fast as soon as you have something that just works. It won&amp;#39;t be the most eloquently written article, nor the most beautiful code, but it&amp;#39;s a simple baseline you can build on.&lt;/p&gt;&lt;p&gt;You can then share this first iteration with your peers and get a feel for whether you&amp;#39;re going in the right direction or the idea is worth pursuing. To me, that makes a great deal more sense than spending weeks on a draft or prototype before asking for input.&lt;/p&gt;&lt;hr
/&gt;&lt;div
class="question"&gt;&lt;h4&gt;&lt;span&gt;Q&lt;/span&gt; You were at AOL before. What are the differences in the culture there versus Google, and how has it impacted your views on software development?&lt;/h4&gt;&lt;/div&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; There&amp;#39;s something special about being a part of a company with such high standards.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Both AOL and Google are companies with terrific engineering teams, and any of my reflections of culture aren&amp;#39;t about any specific groups, more a general observation.&lt;/p&gt;&lt;p&gt;The engineering culture at Google is such that we care a lot about polish and shipping things when we feel they&amp;#39;re just right. There&amp;#39;s something special about being a part of a company with such high standards.&lt;/p&gt;&lt;p&gt;At AOL, I was proud of any of the products or applications we completed, but due to the fast-paced nature of business and competition, delaying launches or releases for polish wasn&amp;#39;t always feasible. I think that&amp;#39;s a reality for many businesses, despite any desire they may have to change that culture.&lt;/p&gt;&lt;p&gt;When it is possible to delay releases to, as Google say, get it &amp;quot;right&amp;quot; I think it can make a world of difference to your users first impressions of your product.&lt;/p&gt;&lt;hr
/&gt;&lt;div
class="question"&gt;&lt;h4&gt;&lt;span&gt;Q&lt;/span&gt; What are you thoughts on the state of the JavaScript community and the direction the TC39 group is taking with respect to ES6?&lt;/h4&gt;&lt;/div&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; I&amp;#39;m pleased with the direction &lt;a
href="http://www.ecma-international.org/memento/TC39.htm"&gt;TC39&lt;/a&gt; have been taking over the past few years.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I&amp;#39;m pleased with the direction &lt;a
href="http://www.ecma-international.org/memento/TC39.htm"&gt;TC39&lt;/a&gt; have been taking over the past few years, which in part has been helped with the involvement of Rick Waldron and Yehuda Katz from the jQuery project. They&amp;#39;ve paid close attention to the patterns and libraries developers have been heavily relying on, and investigating how these could be better solved using platform primitives. I won&amp;#39;t comment on ES6 specifically, but I&amp;#39;m looking forward to seeing modules, classes, &amp;#39;let&amp;#39; and &lt;code&gt;Object.observe()&lt;/code&gt; available more widely.&lt;/p&gt;&lt;p&gt;On the JavaScript community: we&amp;#39;re in a good place but the one thing I wish we would collectively do is spend less time creating new frameworks and more time investing in efforts to improve existing solutions. I think it&amp;#39;s fantastic that developers are spending time learning how to solve problems on their own &amp;#8211; it&amp;#39;s one of the best ways to learn new things &amp;#8211; but if it&amp;#39;s an experiment, make that clear so that other developers don&amp;#39;t expect you to maintain the project. That type of thing only adds to the noise, so please keep support in mind when releasing things!.&lt;/p&gt;&lt;hr
/&gt;&lt;div
class="question"&gt;&lt;h4&gt;&lt;span&gt;Q&lt;/span&gt; A lot of people view Google&amp;#39;s forking of WebKit as a play to allow them to embed Dart into Chrome. Do you see Dart being Google&amp;#39;s ideal over JavaScript?&lt;/h4&gt;&lt;/div&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; One of the big myths out there is that it exists to replace JavaScript.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I was actually super curious to learn more about the goals Dart had when I first joined Google. One of the big myths out there is that it exists to replace JavaScript, but it turns out that this isn&amp;#39;t quite true. &lt;a
href="http://code.google.com/p/dart/"&gt;Dart&lt;/a&gt; is targeted at those developers more familiar with Java, C++, C#, who are trying to build high-performance web apps; and so on that, have certain expectations around their tooling and language. I think that&amp;#39;s a legitimate reason for something like Dart to exist.&lt;/p&gt;&lt;p&gt;As a company, both JavaScript and Dart are technologies that we believe in and invest in. We participate in TC39, working on the future of JavaScript and also continue work on V8, the fast JavaScript engine. The Chrome engineers continue to work to push the web forward with new specs like Web Components. Meanwhile, the team that originally built V8 is now building the Dart VM.&lt;/p&gt;&lt;p&gt;Back to your original question &amp;#8211; I believe forking WebKit was a lot more to do with the divergence of the multi-process architecture between both projects than trying to embed Dart into Chrome. Dart&amp;#39;s a separate open-source project with it&amp;#39;s own goals and you can still get Dartium today (the build of Chromium using the Dart VM).&lt;/p&gt;&lt;hr
/&gt;&lt;div
class="question"&gt;&lt;h4&gt;&lt;span&gt;Q&lt;/span&gt; Now that Blink is in the works, how do you think this help the web, and what do you feel are some new challenges that web developers will face with yet another rendering engine to think about?&lt;/h4&gt;&lt;/div&gt;&lt;p&gt;When I first heard the news about Blink, I was concerned that we&amp;#39;d now have another browser to support.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The reality, however, is that there have already been so many differences between the various WebKit ports that this isn&amp;#39;t going to negatively impact how you develop and test.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;In fact, &lt;a
href="http://www.chromium.org/blink"&gt;Blink&lt;/a&gt; allows us to give developers more of the tools, features and compatibility they need to get the most out of the web as a platform. Long-term it&amp;#39;s going to let us prioritise features that will ease building the next generation of web apps and in the same way that V8 gave us a way to speed up JavaScript, I think Blink is going to let us innovate in ways that will benefit the whole platform.&lt;/p&gt;&lt;hr
/&gt;&lt;div
class="question"&gt;&lt;h4&gt;&lt;span&gt;Q&lt;/span&gt; Google is in an interesting position, where they&amp;#39;re heavily vested in both native apps (Android) and web experiences. As you do developer relations at Google, how do you balance the business directives and priorities for both ecosystems?&lt;/h4&gt;&lt;/div&gt;&lt;p&gt;We get caught up in the debate about native vs. web quite often these days, but don&amp;#39;t talk as much about the need to put our users first. They&amp;#39;re the focus. There are many cases where you can deliver a compelling experience for the web on desktop and mobile and it&amp;#39;ll work fantastic. That said, there are others, where either the platform or mobile browsers still need work. As a business, you often need to make a call on what makes the most sense for your users. I think that, at present, it makes a great deal of sense to offer developers the best platforms possible for making a call on native vs web, and that&amp;#39;s what we do, via Android and Chrome for Mobile.&lt;/p&gt;&lt;hr
/&gt;&lt;div
class="question"&gt;&lt;h4&gt;&lt;span&gt;Q&lt;/span&gt; Stripping away specific web technologies, what should developers be thinking about at a higher level when it comes to the future of the web?&lt;/h4&gt;&lt;/div&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; Reusable components.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Reusable components. Traditionally, a lot of us have developed applications quite vertically, spreading a single concept (whether it be logic or UI) across a few different parts of the project. Not only does this make it harder to maintain the idea but it also makes it difficult to extract and reuse the idea in future applications without a great deal of effort. It also decreases our chances of being able to share the component with others.&lt;/p&gt;&lt;p&gt;Without referring to specific technologies, we&amp;#39;re working on making it easier to define and package up components on the web platform side, and now is a great time to start thinking about how your own apps might be written, if they were broken down into specific components.&lt;/p&gt;&lt;hr
/&gt;&lt;div
class="question"&gt;&lt;h4&gt;&lt;span&gt;Q&lt;/span&gt; Staying on this track, what are the key technologies, end-to-end, that you feel are making the most impact to pushing the web forward? Why?&lt;/h4&gt;&lt;/div&gt;&lt;p&gt;The front-end is seeing a revolution in tooling at the moment with an increasing number of developers starting to use Grunt and explore workflow tools around it like &lt;a
href="http://yeoman.io/"&gt;Yeoman&lt;/a&gt;. Developers are paying more attention to what they can automate and I think that this will help facilitate more time spending building better apps and less time on those manual processes in between.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;a
href="http://angularjs.org/"&gt;&lt;img
src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/angular.jpg" alt="angular" width="564" height="320" class="alignnone size-full wp-image-31672" /&gt;&lt;/a&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt;Going back to the components idea, I think that between web components and front-end package management we have a huge opportunity to really shift the way we develop for the web. &lt;a
href="http://angularjs.org/"&gt;AngularJS&lt;/a&gt; (and Angular directives) have done a great job of re-introducing the idea of reusable blocks of functionality and things are really looking up on the package management side of things, through Bower.&lt;/p&gt;&lt;p&gt;Writing an app with lists you want to make sortable? Great. A few keystrokes at the command-line and you&amp;#39;ve got that. Want to make the items in that list persist when you&amp;#39;re offline? No problem. A few more keystrokes and you&amp;#39;re using a package another developer once had to write to get that capability. Want to turn your list into a reusable component anyone else can use? That&amp;#39;s easy. That&amp;#39;s the future we&amp;#39;re working towards.&lt;/p&gt;&lt;hr
/&gt;&lt;div
class="question"&gt;&lt;h4&gt;&lt;span&gt;Q&lt;/span&gt; Yeoman is your new baby. Why did you feel the need to spin up such an ambitious effort when existing projects seemed to be filling the need?&lt;/h4&gt;&lt;/div&gt; &lt;figure
class="tutorial_image"&gt; &lt;a
href="http://yeoman.io"&gt;&lt;img
src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/yeoman.jpg" alt="yeoman" width="459" height="344" class="alignnone size-full wp-image-31669" /&gt;&lt;/a&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt;We&amp;#39;re fortunate to have a wealth of helpful tools at our disposal on the front-end these days â€“ tools that save us time and make our lives just a little bit easier. Abstractions like &lt;a
href="http://sass-lang.com/"&gt;Sass&lt;/a&gt; and &lt;a
href="http://coffeescript.org/"&gt;CoffeeScript&lt;/a&gt;, frameworks like &lt;a
href="http://twitter.github.io/bootstrap/"&gt;Twitter Bootstrap&lt;/a&gt;, module loaders like &lt;a
href="http://requirejs.org/"&gt;RequireJS&lt;/a&gt;, a never-ending list of MVC and unit testing librariesâ€¦some would say we&amp;#39;re spoiled for choice and it&amp;#39;s interesting seeing how long it can take you to get a project started up.&lt;/p&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; Are you still manually refreshing your browser whenever you make a change to your app?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;As much as these tools work exceptionally well on their own, it can be a tedious process getting them to work together, especially if you have to put together a workflow and build process where they all compile and get optimized succinctly. Even if you do manage to get a solid build process in place, you&amp;#39;re often left having to spend a great deal of time writing out the boilerplate code for your application.&lt;/p&gt;&lt;p&gt;Even then, you have to ask yourself how well this fits in with your day to day workflow. There are several little steps we repetitively do while developing which can more easily be handed off to tooling. Are you still manually refreshing your browser whenever you make a change to your app to preview how they look? Still trying to figure out whether you&amp;#39;re using the latest versions of all your dependencies? Wondering if there was just something that let you get on with coding and forget about a lot of the grunt work?&lt;/p&gt;&lt;p&gt;We were too, which is why we started looking at whether we could give developers a solution to many of these common problems. We tried solving them in a free, open-source project we recently released called Yeoman. Yeoman&amp;#39;s official tagline is that we&amp;#39;re a â€œrobust and opinionated client-side stack, comprised of tools and frameworks that can help developers quickly build compelling web applicationsâ€.&lt;/p&gt;&lt;p&gt;Practically, we&amp;#39;re a series of tools and tasks that help you achieve automate some of the more tedious tasks in front-end development. We&amp;#39;re composed of yo (the scaffolding tool), &lt;a
href="http://gruntjs.com/"&gt;grunt&lt;/a&gt; (the build tool) and &lt;a
href="http://bower.io/"&gt;bower&lt;/a&gt; (for package management).&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;a
href="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/bower.jpg"&gt;&lt;img
src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/bower.jpg" alt="bower" width="600" height="267" class="alignnone size-full wp-image-31675" /&gt;&lt;/a&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt;If you find that you&amp;#39;re still writing boilerplate code for your application, manually managing the dependencies for your apps or putting together your own build system to work with the tools you love, you might find Yeoman a nice way to save yourself some headache.&lt;/p&gt;&lt;hr
/&gt;&lt;div
class="question"&gt;&lt;h4&gt;&lt;span&gt;Q&lt;/span&gt; When you launched Yeoman, Windows wasn&amp;#39;t initially supported. What were the challenges you faced with supporting it, and how can the Windows developer community help in these circumstances?&lt;/h4&gt;&lt;/div&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; The Windows developer community could really help us here.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Creating a command-line tool that works well cross-platform can be a delicate dance. One of the initial challenges with Windows support was that a lot of our team were used to using a *nix system and having access to &lt;a
href="http://mxcl.github.io/homebrew/"&gt;homebrew&lt;/a&gt;/apt-get. We weren&amp;#39;t however as well versed in using PowerShell or &lt;a
href="http://chocolatey.org/"&gt;Chocolatey&lt;/a&gt; (the PowerShell-based Windows equivalent to apt-get) and needed time to understand how well these solutions compared to the tools we had available elsewhere.&lt;/p&gt;&lt;p&gt;It then took time to find (or get) all of the packages we required up on Chocolately as we needed git, phantoms, opting and many others. The situation there has greatly improved since our first release and Windows is now officially supported with Yeoman using the instructions on our homepage.&lt;/p&gt;&lt;p&gt;The Windows developer community could really help us here by advocating for more widespread adoption of tools like Chocolately and helping us reach parity with tools like apt-get. Other than that they&amp;#39;ve been fantastic and we&amp;#39;ve really appreciated the help and support the Windows developer community have offered us throughout our road to compatibility.&lt;/p&gt;&lt;p&gt;I&amp;#39;ve got to give a call out to Sindre Sorhus, Mickael Daniels and Paul Irish, all of whom really helped improve our Windows efforts in the early days.&lt;/p&gt;&lt;hr
/&gt;&lt;div
class="question"&gt;&lt;h4&gt;&lt;span&gt;Q&lt;/span&gt; Along those lines, I have a question based on totally selfish-motivation, since I use Windows. How can *nix and Windows developers collaborate more effectively so that everyone can contribute?&lt;/h4&gt;&lt;/div&gt;&lt;p&gt;At the moment, there are a lot of (fantastic) development tools being written which are not just *nix, but Mac specific because making them cross-platform has it&amp;#39;s own development costs and overhead. I would love to see more open-discussion and development of tools that can work everywhere, but this can&amp;#39;t be done without the help of users.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt; If there&amp;#39;s a tool you want for Windows that you just see on Mac, please be vocal about it &amp;#8211; even better, submit a pull request!&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Try to find out what it would take to bring it to Windows (and elsewhere) and who knows? Maybe the combined efforts of multiple communities would be enough to make something happen.&lt;/p&gt;&lt;hr
/&gt;&lt;div
class="question"&gt;&lt;h4&gt;&lt;span&gt;Q&lt;/span&gt; You&amp;#39;ve written excellent posts, published books and contributed to top OSS projects, like jQuery and Yeoman. Of all your professional accomplishments, is there one thing that really stands out as a proud moment?&lt;/h4&gt;&lt;/div&gt;&lt;p&gt;Releasing my first book, &lt;em&gt;&lt;a
href="http://shop.oreilly.com/product/0636920025832.do"&gt;Learning JavaScript Design Patterns&lt;/a&gt;&lt;/em&gt; (with O&amp;#39;Reilly) was probably the accomplishment that&amp;#39;s given me the greatest satisfaction. It was my largest writing project, and I made the decision for it to be completely open-source from the start &amp;#8211; a call I&amp;#39;ll never regret. Making educational material available to anyone, anywhere whether they can afford it has the potential for a great deal of both good.&lt;/p&gt;&lt;p&gt;It also has the potential to increase your book&amp;#39;s impact, so if you&amp;#39;re an author &amp;#8211; please consider doing it. You won&amp;#39;t regret it!&lt;/p&gt;&lt;hr
/&gt; Thanks so much to Addy for sitting down with it. If you have any of your own questions for him, I&amp;#8217;m sure he won&amp;#8217;t mind answering below in the comments!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=7hx3IvwhzZ0:cYYgk90ZAFw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=7hx3IvwhzZ0:cYYgk90ZAFw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=7hx3IvwhzZ0:cYYgk90ZAFw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=7hx3IvwhzZ0:cYYgk90ZAFw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=7hx3IvwhzZ0:cYYgk90ZAFw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=7hx3IvwhzZ0:cYYgk90ZAFw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=7hx3IvwhzZ0:cYYgk90ZAFw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=7hx3IvwhzZ0:cYYgk90ZAFw:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nettuts/~4/7hx3IvwhzZ0" height="1" width="1"/&gt;</description> <wfw:commentRss>http://net.tutsplus.com/articles/interviews/master-developers-addy-osmani/feed/</wfw:commentRss> <slash:comments>34</slash:comments> <feedburner:origLink>http://net.tutsplus.com/articles/interviews/master-developers-addy-osmani/</feedburner:origLink></item> <item><title>Learn WordPress Plugin Development with Tuts+ Live Workshops</title><link>http://feedproxy.google.com/~r/nettuts/~3/1n0-FeJ02PQ/</link> <comments>http://net.tutsplus.com/articles/news/introduction-to-wordpress-plugin-development-early-bird-tickets-now-available/#comments</comments> <pubDate>Fri, 10 May 2013 15:00:17 +0000</pubDate> <dc:creator>Joel Bankhead</dc:creator> <category><![CDATA[News]]></category> <guid isPermaLink="false">http://net.tutsplus.com/?p=31654</guid> <description>&lt;a
href='http://rss.buysellads.com/click.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31654&amp;c=293476418' target='_blank'&gt;&lt;img
src='http://rss.buysellads.com/img.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31654&amp;c=293476418' border='0' alt='' /&gt;&lt;/a&gt;&lt;p&gt;&lt;strong&gt;We are excited to announce a fantastic new workshop led by Instructor Tom McFarlin: &lt;a
href="http://enva.to/16EzTV6"&gt;Introduction to WordPress Plugin Development&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Are you an aspiring WordPress developer? Are you ready to take the next step and start building your own custom plugins for WordPress? Our newest Tuts+ Live Workshop is the perfect way to get started!&lt;/p&gt;&lt;p&gt;Tickets are a great investment at $99, but places are strictly limited so act fast to make sure you don’t miss out!&lt;br
/&gt; &lt;span
id="more-31654"&gt;&lt;/span&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Introduction to WordPress Plugin Development&lt;/h2&gt;&lt;p&gt;Our newest Tuts+ Live Workshop, Introduction to WordPress Plugin Development, teaches you everything that you need to know to start developing WordPress plugins; from setting up a local development environment, all the way through to building a WordPress plugin that&amp;#8217;s ready for release into the WordPress Plugin Repository.&lt;/p&gt;&lt;p&gt;It&amp;#8217;s led by Instructor Tom McFarlin, a self-employed WordPress developer who divides his time between running his own WordPress development shop, building plugins for WordPress, blogging every day about software development in the context of WordPress, and working for 8BIT (the team responsible for Standard Theme and WP Daily).&lt;/p&gt;&lt;p&gt;Each weekly workshop will last one hour, running over a five week period. You&amp;#8217;ll have the opportunity to follow along with Tom, ask questions live during the workshop, and complete a weekly homework assignment. Not able to make it to the live recording? No problem! All of the workshop recordings will be made available online the day after the live workshop.&lt;/p&gt;&lt;p&gt;&lt;a
href="http://enva.to/16EzTV6"&gt;Learn more about Introduction to WordPress Plugin Development&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;iframe
width="640" height="360" src="http://www.youtube.com/embed/QErsaJMdmCc?rel=0" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Sign Up to Our Newsletter&lt;/h2&gt;&lt;p&gt;If you’re interested in future workshops then definitely &lt;a
href="http://eepurl.com/qnEP5"&gt;join the Tuts+ Live Workshops mailing list&lt;/a&gt; to stay posted on upcoming workshops and get notified as soon as they’re available, the Early Bird tickets for our previous workshops have all sold out, so it’s worth getting ahead of the game!&lt;/p&gt;&lt;p&gt;We’re really excited about new workshop, &lt;a
href="http://enva.to/16EzTV6"&gt;Introduction to WordPress Plugin Development&lt;/a&gt;, but places are strictly limited so act fast to make sure you don’t miss out!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=1n0-FeJ02PQ:VrdQPjAK1E0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=1n0-FeJ02PQ:VrdQPjAK1E0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=1n0-FeJ02PQ:VrdQPjAK1E0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=1n0-FeJ02PQ:VrdQPjAK1E0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=1n0-FeJ02PQ:VrdQPjAK1E0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=1n0-FeJ02PQ:VrdQPjAK1E0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=1n0-FeJ02PQ:VrdQPjAK1E0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=1n0-FeJ02PQ:VrdQPjAK1E0:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nettuts/~4/1n0-FeJ02PQ" height="1" width="1"/&gt;</description> <wfw:commentRss>http://net.tutsplus.com/articles/news/introduction-to-wordpress-plugin-development-early-bird-tickets-now-available/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://net.tutsplus.com/articles/news/introduction-to-wordpress-plugin-development-early-bird-tickets-now-available/</feedburner:origLink></item> <item><title>10 Tips for Learning a New Technology</title><link>http://feedproxy.google.com/~r/nettuts/~3/r2a0hxpckRs/</link> <comments>http://net.tutsplus.com/articles/general/10-tips-for-learning-a-new-technology/#comments</comments> <pubDate>Thu, 09 May 2013 02:07:00 +0000</pubDate> <dc:creator>Pavan Podila</dc:creator> <category><![CDATA[General]]></category> <guid isPermaLink="false">http://net.tutsplus.com/?p=31631</guid> <description>&lt;a
href='http://rss.buysellads.com/click.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31631&amp;c=769132278' target='_blank'&gt;&lt;img
src='http://rss.buysellads.com/img.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31631&amp;c=769132278' border='0' alt='' /&gt;&lt;/a&gt;&lt;p&gt;We live in a very exciting time. Never before has education been so cheaply available to the masses (if not free). The medium, itself, has made tectonic shifts from a classroom setting, to blogs, screencasts and complete university classes, as a set of videos and interactive forums. Given these resources, there&amp;#8217;s absolutely no excuse not to dive in and learn. However, with such a wealth of resources, filtering through the options can often become overwhelming. In this article, I will outline a simple process to kick-start your education.&lt;/p&gt;&lt;p&gt;&lt;span
id="more-31631"&gt;&lt;/span&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Although my suggestions will primarily pertain to software development, these principles are certainly applicable to other fields.&lt;/p&gt;&lt;/blockquote&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;1.&lt;/span&gt; Overcoming Inertia&lt;/h2&gt;&lt;div
class='tutorial_image'&gt;&lt;img
src='http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/inertia.jpg' alt='Inertia' title='' border='0'&gt;&lt;/div&gt;&lt;p&gt;Learning something new always begins by first overcoming the inertia to make the first move. This is the same inertia you feel when you want to change the TV channel, but the remote isn&amp;#39;t nearby! Thankfully, there are some simple techniques to get excited and motivated. One that has worked really well for me is the concept of &lt;a
href="http://tinyhabits.com/"&gt;Tiny Habits&lt;/a&gt;. Rather than becoming overwhelmed by the task at hand, take a tiny step and do something to get started. Using the &lt;em&gt;&amp;quot;get the TV remote&amp;quot;&lt;/em&gt; example, start by wiggling your toes, then bend forward, then push yourself away from the couch. Next, try to fall off onto the floor, and finally get up. By following a series of tiny steps, you will overcome your inertia and the task won&amp;#39;t seem as overwhelming. This same idea can be applied to learning new skills. It&amp;#8217;s all about tiny steps.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;2 -&lt;/span&gt; Watch the Pros&lt;/h2&gt;&lt;div
class='tutorial_image'&gt;&lt;img
src='http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/pro.jpg' alt='Pro' title='' border='0'&gt;&lt;/div&gt;&lt;p&gt;The first step, when picking up a new skill, is to determine &lt;em&gt;what&lt;/em&gt; to learn. This could be anything you feel passionate about, and have a genuine interest in exploring further. It&amp;#8217;s important to have this strong inclination, as it will provide you with the necessary fuel, during those low times. Once you decide what to learn, be it a new programming language, an application framework, or a tool, research inspiring work done by their respective communities. You may find it on &lt;a
href="http://www.youtube.com/channels/recommended_for_you"&gt;YouTube&lt;/a&gt;, &lt;a
href="https://vimeo.com/channels/staffpicks"&gt;Vimeo&lt;/a&gt;, &lt;a
href="https://news.ycombinator.com/newest"&gt;HackerNews&lt;/a&gt;, blogs or even from one of your &lt;a
href="https://twitter.com/i/discover"&gt;Twitter&lt;/a&gt; friends. Reviewing what others have done will give you confidence that you, too, can do it!&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;3 -&lt;/span&gt; Let the Information Flow Begin&lt;/h2&gt;&lt;div
class='tutorial_image'&gt;&lt;img
src='http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/info-flow.jpg' alt='Information Flow' title='' border='0'&gt;&lt;/div&gt;&lt;p&gt;Once you cross the stage of convincing yourself about the thing you want to learn, it&amp;#8217;s time that become a sponge, and start absorbing knowledge. Begin with some Google searching on &amp;quot;beginner tutorials&amp;quot; related to your topic. As you know, Nettuts+ offers hundreds upon hundreds of tutorials. Check here as well. &lt;a
href="http://www.stackoverflow.com"&gt;StackOverflow&lt;/a&gt; is one place where you will surely find links to a plethora of resources. Alternatively, &lt;a
href="http://www.quora.com/Learning-to-Program/What-are-the-best-sites-for-learning-programming"&gt;Quora&lt;/a&gt; is an excellent place to search for answers. Once you sift through these links, you may wish to take a more concentrated dose by looking for the best books on the topic. Personally I refer to &lt;a
href="http://www.amazon.com/books-used-books-textbooks/b/ref=sa_menu_bo?ie=UTF8&amp;amp;node=283155"&gt;Amazon&lt;/a&gt; for hunting down highly rated books.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;4 -&lt;/span&gt; Listen and Watch&lt;/h2&gt;&lt;div
class='tutorial_image'&gt;&lt;img
src='http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/watch.jpg' alt='Watch' title='' border='0'&gt;&lt;/div&gt;&lt;p&gt;As you delve deeper into the pool of knowledge, you will want to add other forms of information &amp;#8211; namely, podcasts and screencasts. I encourage you to browse through &lt;a
href="http://www.apple.com/education/itunes-u/"&gt;iTunesU&lt;/a&gt;, which offers complete classes on a variety of topics from some of the best institutions in the world. This is particularly helpful for those who prefer an academic setting.&lt;/p&gt;&lt;p&gt;These days, there are a handful of websites that offers online education. Look no further than our very own &lt;a
href="http://tutsplus.com"&gt;Tuts+ Premium&lt;/a&gt;. Hoping to learn PHP or JavaScript? There&amp;#8217;s &lt;a
href="https://tutsplus.com/courses/?q=true&amp;#038;filter_topic=35"&gt;no better resource on the web&lt;/a&gt;. Alternatively, you might consider:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a
href="https://www.udemy.com/"&gt;Udemy&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="http://www.codecademy.com"&gt;CodeAcademy&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="http://www.codeschool.com/"&gt;CodeSchool&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;You can also watch conference presentations, such as &lt;a
href="http://www.youtube.com/playlist?list=PL56D792A831D0C362"&gt;Google IO&lt;/a&gt; on YouTube, or &lt;a
href="http://www.confreaks.com/"&gt;Confreaks&lt;/a&gt; for free!&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;5 -&lt;/span&gt; Time for Action&lt;/h2&gt;&lt;div
class='tutorial_image'&gt;&lt;img
src='http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/action.jpg' alt='Action' title='' border='0'&gt;&lt;/div&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; The best way to learn is by doing.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Okay, you&amp;#8217;ve read countless tutorials, watched videos, and have a better understanding of the technology that you&amp;#8217;ve been hoping to learn. What now? Well, it&amp;#8217;s time to put your knowledge to the test. Ultimately, the best way to learn is by doing.&lt;/p&gt;&lt;p&gt;Pick a personal project that you can build using this new technology. Design some simple features and implement them. You will most definitely hit some stumbling blocks. When this happens, research the solution on StackOverflow or Google. You are now on a journey to become an expert in that technology. The more failures and road blocks you encounter, the wiser you will be. There is a saying that &amp;quot;the experts are ones who have made the most mistakes.&amp;quot; It means they&amp;#8217;ve tried crazy things and pushed the limits of a technology. As a result, they&amp;#8217;ve acquired an intimate understanding of how it works. With such insight, they are able to bend the tech to their will and wield Jedi powers (&lt;em&gt;for good, of course&lt;/em&gt;).&lt;/p&gt;&lt;p&gt;These powers are also within your reach.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;6 -&lt;/span&gt; Blogging&lt;/h2&gt;&lt;div
class='tutorial_image'&gt;&lt;img
src='http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/blog.jpg' alt='Blogging' title='' border='0'&gt;&lt;/div&gt;&lt;p&gt;As you embark on your journey, it&amp;#8217;s helpful to chronicle the steps (or missteps) you took along the way. Blogs are easily the most popular form of expression in the tech community. It&amp;#8217;s part of our DNA. When you put a pen to your learnings, you&amp;#8217;re forcing yourself to become more cohesive in your thoughts, bringing some structure into the dispersed pieces of knowledge that you have accumulated. Who knows, in the process, you just might be educating someone else on the Internet. Pay it forward when you can.&lt;/p&gt;&lt;p&gt;If you&amp;#8217;d like to take things a step further (as writers do every day here on Nettuts+), can take this a step further and create screencasts, which is preferred by most visual learners. Overall, blogging helps you build your communication skills, which is as important as the technology you are learning.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;7 -&lt;/span&gt; Feel the Pulse&lt;/h2&gt;&lt;div
class='tutorial_image'&gt;&lt;img
src='http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/pulse.jpg' alt='Pulse' title='' border='0'&gt;&lt;/div&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; Technology matures when people do crazy and sometimes unthinkable things.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Social Networks have become a universal way of staying in touch and discovering new things. Twitter and Facebook are the primary suspects for information, but there are more focused websites, like the previously mentioned Quora, that have a wide-ranging set of topics, which people may vote and comment on. It&amp;#8217;s a great place to find answers and opinions from well-known individuals with real-life experiences. In fact, a quick search on Quora for &lt;a
href="http://www.quora.com/Learning-New-Things"&gt;other perspectives on learning&lt;/a&gt;, reveals an interesting set of results.&lt;/p&gt;&lt;p&gt;Scanning the ever-growing set of questions on StackOverflow can also be a fun way to review the way in which others are pushing the limits of a particular technology. In fact, technology matures when people do crazy and sometimes unthinkable things with it.&lt;/p&gt;&lt;p&gt;If you want to feel the pulse of a technology, and determine whether it&amp;#8217;s worth learning, try a search on StackOverflow to see the breadth and depth of the community. The &lt;a
href="http://stackoverflow.com/questions?sort=votes"&gt;Most Voted&lt;/a&gt;, &lt;a
href="http://stackoverflow.com/questions?sort=featured"&gt;Featured&lt;/a&gt; questions are excellent candidates for this sort of exploration. You can also carry out a similar exploration on &lt;a
href="https://github.com/explore"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;8 -&lt;/span&gt; Meetups and Conferences&lt;/h2&gt;&lt;div
class='tutorial_image'&gt;&lt;img
src='http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/meetup.jpg' alt='Meetup' title='' border='0'&gt;&lt;/div&gt;&lt;p&gt;Although social networks are great, nothing can substitute real human connection. It is quite likely that you have a &lt;a
href="http://www.meetup.com/"&gt;Meetup&lt;/a&gt; group in a place near you, where you&amp;#8217;ll find several like-minded folks. You will learn about interesting projects that others are working on, while also getting some of your tricky problems solved!. On a related note, conferences, too, are a great place to share experiences and enrich your already growing skill-set.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;9 -&lt;/span&gt; GitHub&lt;/h2&gt;&lt;div
class='tutorial_image'&gt;&lt;img
src='http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/octocat.jpg' alt='Octocat' title='' border='0'&gt;&lt;/div&gt;&lt;p&gt;&lt;a
href="https://github.com/explore"&gt;GitHub&lt;/a&gt; is the iconic landmark for the world of open-source projects. It&amp;#8217;s a treasure trove of knowledge and creativity, expressed in the form of code. Once you feel comfortable with a particular technology, your next step should be to explore GitHub to find interesting projects. Read the source code. Read as much as you can. In doing so, you can learn a variety of things, such as:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;How to organize large projects&lt;/li&gt;&lt;li&gt;Interesting libraries that projects are using&lt;/li&gt;&lt;li&gt;Code patterns and overall design&lt;/li&gt;&lt;li&gt;Documentation style&lt;/li&gt;&lt;li&gt;Testing patterns&lt;/li&gt;&lt;li&gt;Solutions to odd issues, pointed out in the Issues section of the project&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;All of this knowledge is just waiting to be devoured. Interestingly, and to your benefit, it only comes with a simple price tag: &lt;em&gt;curiosity&lt;/em&gt;.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;10 -&lt;/span&gt; Concentrated Learning&lt;/h2&gt;&lt;div
class='tutorial_image'&gt;&lt;img
src='http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/05/dose.jpg' alt='Dose' title='' border='0'&gt;&lt;/div&gt;&lt;p&gt;If you worry that the process outlined above is too slow, you might also try a fast-track approach. You may have heard about the &amp;quot;Learn &lt;em&gt;X&lt;/em&gt; in 24 hours&amp;quot;, but that is not what I am referring to. A more pragmatic time-line is probably a few weeks. If that seems reasonable, you can try something like &lt;a
href="http://pragprog.com/book/btlang/seven-languages-in-seven-weeks"&gt;Seven Languages in Seven Weeks&lt;/a&gt; or &lt;a
href="http://pragprog.com/book/btlang/seven-databases-in-seven-weeks"&gt;Seven Databases in Seven Weeks&lt;/a&gt;. Although these books refer to languages and databases, you could do the same with other technologies.&lt;/p&gt;&lt;p&gt;A slightly different style would be to &lt;a
href="http://learncodethehardway.org/"&gt;learn things the &amp;quot;hard way&amp;quot;&lt;/a&gt;. The idea here is to accept upfront that nobody can master a skill unless it is practiced daily. So to gain expertise, you practice by working through countless exercises. In a similar vein, you also have &lt;a
href="http://codekata.pragprog.com/"&gt;Katas&lt;/a&gt; and &lt;a
href="https://www.google.com/search?q=koans"&gt;Koans&lt;/a&gt;, that encourage solving problems in the language of your choice. These will introduce you to concepts and techniques that may initially be alien to you. That&amp;#8217;s the point! If you really want to displace yourself from your comfort zone, give them a shot!&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Learn an Orthogonal Skill&lt;/h2&gt;&lt;blockquote
class="pullquote"&gt;&lt;p&gt; Your right-brain processes information in a very different fashion.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Programming is primarily a left-brain activity. It leverages the analytical part of the brain that looks for a step-by-step approach to solving problems. To appreciate the power of the right-brain, take up a creative activity, such as painting, 3D-modeling, origami, playing an instrument, or even building photo books out of your family albums. In fact, programming requires a great deal of creativity. You might have already experienced this, if you&amp;#8217;ve ever found solutions to obtuse problems in your sleep. This is because your right-brain processes information in a very different fashion, and can compile ideas from all over the place. Andy Hunt, from the pragmatic bookshelf, wrote a book on this topic: &lt;a
href="http://pragprog.com/book/ahptl/pragmatic-thinking-and-learning"&gt;Pragmatic Thinking and Learning: Refactor Your Wetware&lt;/a&gt;. If you want to be firing on all synapses, pick up a skill orthogonal to what you already do.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Summary&lt;/h2&gt;&lt;p&gt;Acquiring a new skill is always exciting. It&amp;#8217;s the start of a new experience that will shape your thinking. But first, you must overcome your inertia. Once you do, your journey to absorb knowledge from every facet of the web begins. I hope that the process outlined above has given you some ideas for approaching this long road.&lt;/p&gt;&lt;p&gt;If you have a different approach to learning, I&amp;#8217;d love to learn more about it. Feel free to leave a comment, while I leave you with these inspiring links:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a
href="http://pragprog.com/book/tpp/the-pragmatic-programmer"&gt;From Journeyman to Master&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="http://pragprog.com/book/cfcar2/the-passionate-programmer"&gt;Passionate Programmer&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="https://vimeo.com/36579366"&gt;Inventing on Principle&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="https://vimeo.com/64895205"&gt;Stop Drawing Dead Fish&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="http://www.lighttable.com/"&gt;LightTable&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=r2a0hxpckRs:50YOPm3SVxk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=r2a0hxpckRs:50YOPm3SVxk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=r2a0hxpckRs:50YOPm3SVxk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=r2a0hxpckRs:50YOPm3SVxk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=r2a0hxpckRs:50YOPm3SVxk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=r2a0hxpckRs:50YOPm3SVxk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?i=r2a0hxpckRs:50YOPm3SVxk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/nettuts?a=r2a0hxpckRs:50YOPm3SVxk:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nettuts/~4/r2a0hxpckRs" height="1" width="1"/&gt;</description> <wfw:commentRss>http://net.tutsplus.com/articles/general/10-tips-for-learning-a-new-technology/feed/</wfw:commentRss> <slash:comments>51</slash:comments> <feedburner:origLink>http://net.tutsplus.com/articles/general/10-tips-for-learning-a-new-technology/</feedburner:origLink></item> </channel> </rss><!-- Dynamic Page Served (once) in 0.961 seconds -->
