I just finished reading Uncle Bob Martin's book The Clean Coder and it is a great read for any software developer who cares about their craft. This book already has taken its place among the books that have changed the way I look at software development and my carreer (i.e. The Pragmatic Programmer, Code Complete).
If you haven't read this book, you should go out and read it. I'd suggest getting the actual book instead of the Kindle version so you can write notes in the margins.
Sam Merrell
What we do is never understood, but only praised and blamed. -Nietzsche
Friday, July 08, 2011
Sunday, December 12, 2010
Trying out BDD With SpecFlow and Selenium - Part 1
One of the biggest things I learned when I was working as a tester at IBM is how important testing really is in applications large and small. While I've moved on to full time development the test side of my work has really never gone away. While working on updating one of the features of the Extend Health side we've decided that it would be a good time to try out some testing that hasn't been covered much.
So with that we've decided to try out some Behavior Driven Development and write some integration tests for this new feature. Since we're a .NET shop we've decided to give SpecFlow a try instead of running Cucumber straight on Ruby. Fortunately if we ever decide to switch from SpecFlow to Cucumber our features will transition directly since they are in the Gherkin format. The main reason we're trying out this Gherkin format is that it gives us a Business Readable Domain Specific Language.
The advantage that this would buy us is that we could document the sites features in a way that both the business development team could read and write features in a way that we in development could directly write tests against them. This also helps us in development because we have a solid list of features we know that we need to implement and that we should be less likely to either break that feature or miss it altogether. This is one thing that Unit Tests just don't really buy you. It would be easy enough to write a suite of Unit Tests that don't cover the actual feature itself as described by the business.
So lets get to what a test in SpecFlow looks like.
So there we go, that's pretty simple looking right? That right there is the beauty of the Gherkin syntax to me. It is structured enough that we crazy programmer types could turn that into some tests (and we'll get there) but the business types can also read and understand what is going on here. Oh and because I think this is awesome, using Cucumber you can write this in a ton of different spoken languages.
One thing I'd like to point out though, is that while features and scenarios look really simple, I've found so far that the hardest part is writing a clear feature and scenario. Writing unit tests aren't very difficult since you break that down as much as possible. It all comes down to communication really, finding the best way to describe a feature without getting too broad or too detailed. The cucumber docs do have a really great example (scroll to the bottom) of applying the Five Whys to really decide why you want a feature and how to describe it.
So now that we've had a chance to check out the Gherkin syntax that SpecFlow uses, in my next post I'll show the actual code behind this feature and how we're starting to use Selenium to verify these features.
So with that we've decided to try out some Behavior Driven Development and write some integration tests for this new feature. Since we're a .NET shop we've decided to give SpecFlow a try instead of running Cucumber straight on Ruby. Fortunately if we ever decide to switch from SpecFlow to Cucumber our features will transition directly since they are in the Gherkin format. The main reason we're trying out this Gherkin format is that it gives us a Business Readable Domain Specific Language.
The advantage that this would buy us is that we could document the sites features in a way that both the business development team could read and write features in a way that we in development could directly write tests against them. This also helps us in development because we have a solid list of features we know that we need to implement and that we should be less likely to either break that feature or miss it altogether. This is one thing that Unit Tests just don't really buy you. It would be easy enough to write a suite of Unit Tests that don't cover the actual feature itself as described by the business.
So lets get to what a test in SpecFlow looks like.
Feature: Share this post In order to increase traffic to the blog to increase advertising revenue I want readers to share posts they find interesting Scenario: Share on Twitter Given a person reading a blog post When they press the "Tweet This" button Then the Twitter popup should appear
So there we go, that's pretty simple looking right? That right there is the beauty of the Gherkin syntax to me. It is structured enough that we crazy programmer types could turn that into some tests (and we'll get there) but the business types can also read and understand what is going on here. Oh and because I think this is awesome, using Cucumber you can write this in a ton of different spoken languages.
One thing I'd like to point out though, is that while features and scenarios look really simple, I've found so far that the hardest part is writing a clear feature and scenario. Writing unit tests aren't very difficult since you break that down as much as possible. It all comes down to communication really, finding the best way to describe a feature without getting too broad or too detailed. The cucumber docs do have a really great example (scroll to the bottom) of applying the Five Whys to really decide why you want a feature and how to describe it.
So now that we've had a chance to check out the Gherkin syntax that SpecFlow uses, in my next post I'll show the actual code behind this feature and how we're starting to use Selenium to verify these features.
Sunday, December 05, 2010
One Week Down Learning JavaScript and jQuery
Like I mentioned in my last post I've started a new job this Monday at Extend Health working in .NET with a bunch of fun technologies including ASP.NET MVC2, Nhibernate, some FubuMVC and using a bunch of jQuery. At my last job at Mediaport I had just started teaching myself both ASP.NET MVC2 and digging deeper into JavaScript and jQuery. Now that my first week is done at Extend Health I've been happily digging through all the code and working on my assignment to study some more on JavaScript.
This week I have been reading Douglas Crockford's book JavaScript: The Good Parts. I had watched a video of his talk about JavaScript's good parts at Yahoo! before but reading this book has really opened my eyes to JavaScript and the power as well as pitfalls of the language. It is definitely going to take some time to fully appreciate the power JavaScript has.
So onto a little bit of what I've been up to during my first week.
jQuery Templates:
Besides just trying to become more familiar with JavaScript as well as jQuery I was looking at places we might be able to try out jQuery Templates which is one of the plugins developed by Microsoft that have recently become official parts of jQuery. After playing a little bit with the jQuery Templates I have to say that I really like them. I've seen a few template plugins that rely on you dumping all the templates into big ugly strings and with jquery-tmpl you can avoid all that. Here is a quick sample of one:
Pretty straightforward but the nice thing is that you don't have any ugly string to muck with. Instead you get a nicely encapsulated template which has a competent set of features including the each, if/else, and nesting of templates. I'll have to use it some more but this plugin looks really great and should get even better over time.
jQuery Datalink and Knockout.js
Along with the jQuery Templates I checked out another plugin from Microsoft called jQuery Datalink. The datalink plugin lets you bind a JavaScript object to a form and keep the two in sync without having to write a bunch of extra code. Here is a quick example of binding a form to a JavaScript object.
With that, we've bound the person object to the form. This will give person the attributes firstName and lastName. Now whenever the text changes for the firstName or lastName text inputs the person object will be updated. Pretty simple, but it could prove useful.
While looking at the jQuery Datalink plugin I heard about Knockout.js which also provides databinding but takes a different approach than jQuery Datalink. In Knockout things are much more JavaScript oriented and is based of of the Model View ViewModel (MVVM) pattern.
So in Knockout, we create a view model that we will bind its attributes to in the HTML.
And with that whenever the underlying JavaScript object changes the values will be updated in the HTML. That is just a simple example of what Knockout can do. Knockout looks like a really interesting project and the style of binding should feel familiar to any Silverlight or WPF developers since that is what this is based off. Hopefully I'll have some more time to write about Knockout.js as it seems like a really interesting project.
My first week has been really fun and I'm really looking forward to mastering JavaScript and digging much deeper in to ASP.NET MVC and C#. So here's to learning more code!
This week I have been reading Douglas Crockford's book JavaScript: The Good Parts. I had watched a video of his talk about JavaScript's good parts at Yahoo! before but reading this book has really opened my eyes to JavaScript and the power as well as pitfalls of the language. It is definitely going to take some time to fully appreciate the power JavaScript has.
So onto a little bit of what I've been up to during my first week.
jQuery Templates:
Besides just trying to become more familiar with JavaScript as well as jQuery I was looking at places we might be able to try out jQuery Templates which is one of the plugins developed by Microsoft that have recently become official parts of jQuery. After playing a little bit with the jQuery Templates I have to say that I really like them. I've seen a few template plugins that rely on you dumping all the templates into big ugly strings and with jquery-tmpl you can avoid all that. Here is a quick sample of one:
Pretty straightforward but the nice thing is that you don't have any ugly string to muck with. Instead you get a nicely encapsulated template which has a competent set of features including the each, if/else, and nesting of templates. I'll have to use it some more but this plugin looks really great and should get even better over time.
jQuery Datalink and Knockout.js
Along with the jQuery Templates I checked out another plugin from Microsoft called jQuery Datalink. The datalink plugin lets you bind a JavaScript object to a form and keep the two in sync without having to write a bunch of extra code. Here is a quick example of binding a form to a JavaScript object.
var person = {}; $("form").bind(person);
With that, we've bound the person object to the form. This will give person the attributes firstName and lastName. Now whenever the text changes for the firstName or lastName text inputs the person object will be updated. Pretty simple, but it could prove useful.
While looking at the jQuery Datalink plugin I heard about Knockout.js which also provides databinding but takes a different approach than jQuery Datalink. In Knockout things are much more JavaScript oriented and is based of of the Model View ViewModel (MVVM) pattern.
So in Knockout, we create a view model that we will bind its attributes to in the HTML.
The first name is The last name is
var myViewModel = { personFirstName: ko.observable('Bob'), personLastName: ko.observable('Marley'), } ko.applyBindings(myViewModel);
And with that whenever the underlying JavaScript object changes the values will be updated in the HTML. That is just a simple example of what Knockout can do. Knockout looks like a really interesting project and the style of binding should feel familiar to any Silverlight or WPF developers since that is what this is based off. Hopefully I'll have some more time to write about Knockout.js as it seems like a really interesting project.
My first week has been really fun and I'm really looking forward to mastering JavaScript and digging much deeper in to ASP.NET MVC and C#. So here's to learning more code!
Monday, November 08, 2010
A Change of Pace
It has been a while since I last posted anything up on my blog (apparently when IBM laid me off) so I'm starting to sense a bit of a trend here. :)
Since my last post I got a job with a couple of great friends at Mediaport Entertainment doing .NET development starting with Silverlight and ASP.NET. It has been a really great experience to get back into .NET from Java and I've had lots of fun picking up the many ways C# has changed from its early Java-clone days. We've been working on the next version of our web store and I helped decide that we should move away from Silverlight and ASP.NET to give ASP.NET MVC a try. It has been a great experience learning web development with this platform and I'm excited to keep building my skills in web development and learning Javascript / jQuery.
But now I'm moving to a new company that I'm really excited about. Extend Health is where I've decided to move to now and I am really looking forward to starting there. They have a great team of developers, many of them Neumont graduates. I'll still be doing .NET and ASP.NET MVC development but I feel I'm going to have a great time learning from all the developers there.
And to finish off Extend Health was the first company I've had an interview where I was asked to build a web app and on the next interview we would discuss it. I have to say I love that idea for an interview so much better than whiteboarding a simple linked list implementation!
Since my last post I got a job with a couple of great friends at Mediaport Entertainment doing .NET development starting with Silverlight and ASP.NET. It has been a really great experience to get back into .NET from Java and I've had lots of fun picking up the many ways C# has changed from its early Java-clone days. We've been working on the next version of our web store and I helped decide that we should move away from Silverlight and ASP.NET to give ASP.NET MVC a try. It has been a great experience learning web development with this platform and I'm excited to keep building my skills in web development and learning Javascript / jQuery.
But now I'm moving to a new company that I'm really excited about. Extend Health is where I've decided to move to now and I am really looking forward to starting there. They have a great team of developers, many of them Neumont graduates. I'll still be doing .NET and ASP.NET MVC development but I feel I'm going to have a great time learning from all the developers there.
And to finish off Extend Health was the first company I've had an interview where I was asked to build a web app and on the next interview we would discuss it. I have to say I love that idea for an interview so much better than whiteboarding a simple linked list implementation!
Tuesday, March 02, 2010
Time for a Change
This Monday has proven to be an interesting one. I arrived at work in the morning and managed to start getting into a productive groove, which can be difficult on a Monday, only to have everything flopped upside down by lunch. I had a meeting with my manager and found out that I've been part of a Resource Action (IBM-speak for layoff) so as of March 1st I am back on the market for a new job. Even though I was aware something like this might come up I have to admit I'm still trying to get my head around what has happened. My first job and also my first layoff... Live and learn I suppose.
I've had a lot of fun at IBM and I've really had a great learning experience of life inside a company as big as IBM. Going straight from school to IBM was daunting to me but I feel really great that I have accomplished something for myself. I've met some really great people that I hope to keep in contact with once I find a new job. So as my time with IBM has come to an end I am looking forward anxiously to the next thing for me to work on. Thanks for all the good times IBM!
Now that all that is out of the way, if you happen to be hiring or know anyone who may be hiring I'd love to hear from you! :-) You can find me on LinkedIn or check my Stack Overflow CV.
I've had a lot of fun at IBM and I've really had a great learning experience of life inside a company as big as IBM. Going straight from school to IBM was daunting to me but I feel really great that I have accomplished something for myself. I've met some really great people that I hope to keep in contact with once I find a new job. So as my time with IBM has come to an end I am looking forward anxiously to the next thing for me to work on. Thanks for all the good times IBM!
Now that all that is out of the way, if you happen to be hiring or know anyone who may be hiring I'd love to hear from you! :-) You can find me on LinkedIn or check my Stack Overflow CV.
Sunday, January 17, 2010
Learning Scala pt 1: First Impressions
My first foray into learning Scala with the help of O'Reilly's Learning Scala, and the interwebs. I'll be posting things as I learn them in a way to help cement my understanding of the language and so if I'm wrong, people can call me on it.
As a Java programmer, I've been very interested in watching all the languages that are beginning to spring up around the JVM. From JRuby, Jython, Groovy, Clojure, and Scala they've all been interesting to watch take the JVM to new heights beyond Java. So far, I've been mostly interested in languages started on the JVM (though JRuby and Jython look nice) since they are designed from the ground up to take advantage of the vast number of Java libraries in a natural way.
My first dabble was with Groovy which takes many of its ideas from Ruby, but can still be written in a very Java-centric way. Specifically, Groovy was written to be more of a superset of Java including duck typing and Closures into the mix and letting you write applications much more quickly and concisely than one could in Java. Unfortunately I haven't really played with Groovy much recently but it seems like it would be a great JVM-based glue language or for writing up a quick prototype.
Scala has been drawing me in over the past couple weeks and feels like it could be a full replacement language for Java where with Groovy it felt like an additional tool in my Java workbench. After reading Chapter 1 of Learning Scala here are my impressions of Scala thus far:
Functional and Object Oriented
From the start Scala mixes both functional aspects (much of which still confuse my Object Oriented mind so far), and Object Oriented programming. We have Classes and inheritance but also have pattern matching and Actors.
Less Verbose than Java
Scala, like many other languages, is less verbose than Java in several ways. First, there is no need for the semicolon (in most cases), or even for return statements of methods. Scala will usually handle these things for you, so a method foo, that adds two numbers, could be written like this:
A nice feature of Scala is that you can choose to specifically type your variables or let Scala figure that out. In Scala, the type comes after the variable name to make it easy to parse when the variable is not typed.
Strange at First
As a Java programmer I've gotten pretty used to how things are with Java so beginning to learn Scala has left a few parts of my mind that stick out.
Method Names
Scala is much more flexible in what a method name can be, this includes these characters to name a few: "+,-,<,>,*,/,?,!". This seemed very unnatural to me coming from Java where this is not possible. This also is confusing because it looks like operator overloading but actually isn't operator overloading, these are method names, so one could define a "+" method or a ">" method and be perfectly fine with Scala.
This will definitely take some getting used to but I think it could be very handy especially when the need for a DSL arises.
No static keyword
With Java, declaring a class-level variable is as easy as tacking the static keyword to it. With Scala, there is no static keyword, instead, for class level variables you use the object keyword instead of class.
Overall Scala isn't too different from Java on first glance. While there certainly will be more differences, it is easy enough for me to start jumping in and playing around with Scala.
As a Java programmer, I've been very interested in watching all the languages that are beginning to spring up around the JVM. From JRuby, Jython, Groovy, Clojure, and Scala they've all been interesting to watch take the JVM to new heights beyond Java. So far, I've been mostly interested in languages started on the JVM (though JRuby and Jython look nice) since they are designed from the ground up to take advantage of the vast number of Java libraries in a natural way.
My first dabble was with Groovy which takes many of its ideas from Ruby, but can still be written in a very Java-centric way. Specifically, Groovy was written to be more of a superset of Java including duck typing and Closures into the mix and letting you write applications much more quickly and concisely than one could in Java. Unfortunately I haven't really played with Groovy much recently but it seems like it would be a great JVM-based glue language or for writing up a quick prototype.
Scala has been drawing me in over the past couple weeks and feels like it could be a full replacement language for Java where with Groovy it felt like an additional tool in my Java workbench. After reading Chapter 1 of Learning Scala here are my impressions of Scala thus far:
Functional and Object Oriented
From the start Scala mixes both functional aspects (much of which still confuse my Object Oriented mind so far), and Object Oriented programming. We have Classes and inheritance but also have pattern matching and Actors.
Less Verbose than Java
Scala, like many other languages, is less verbose than Java in several ways. First, there is no need for the semicolon (in most cases), or even for return statements of methods. Scala will usually handle these things for you, so a method foo, that adds two numbers, could be written like this:
def foo = { 1 + 1 }Which returns an Integer.
A nice feature of Scala is that you can choose to specifically type your variables or let Scala figure that out. In Scala, the type comes after the variable name to make it easy to parse when the variable is not typed.
Strange at First
As a Java programmer I've gotten pretty used to how things are with Java so beginning to learn Scala has left a few parts of my mind that stick out.
Method Names
Scala is much more flexible in what a method name can be, this includes these characters to name a few: "+,-,<,>,*,/,?,!". This seemed very unnatural to me coming from Java where this is not possible. This also is confusing because it looks like operator overloading but actually isn't operator overloading, these are method names, so one could define a "+" method or a ">" method and be perfectly fine with Scala.
This will definitely take some getting used to but I think it could be very handy especially when the need for a DSL arises.
No static keyword
With Java, declaring a class-level variable is as easy as tacking the static keyword to it. With Scala, there is no static keyword, instead, for class level variables you use the object keyword instead of class.
class foo() { // Instance variables go here } object foo() { // Class level variables go here }
Overall Scala isn't too different from Java on first glance. While there certainly will be more differences, it is easy enough for me to start jumping in and playing around with Scala.
Saturday, October 03, 2009
JCP Death spiral or "Normal for a Maturing Language"
140 characters wasn't enough to write my thoughts down on Stephen Colebourne's blog post about the JCP I came across via @snoopdave. Since I live in Java land I've thought a lot about the JCP, Java, and how things will be once Oracle absorbs Sun. No one really knows what Oracle may, or may not do with Java and the JCP but one thing I'm certain of is that things are changing whether Oracle does anything about it or not.
I've been following the long saga between The Apache Software Foundation and the Sun over Apache Harmony for a while now and there are definitely problems with the JCP that need to be resolved. Colebourne's post shows the declining trend in numbers of JSRs submitted to the JCP and brings up the question as to whether this is a sign of the times for the JCP or something normal for a maturing language such as Java.
I think the answer is a bit of both. As Colebourne points out, his chart only includes new JSRs and not ones that are in maintenance mode or being updated, such as Java EE 6 for example (which connects about 30 other JSRs, most of which are not new). Since Java is a large platform that has been around for quite some time now that seems very normal to me from a mature language.
The other part I'm starting to see comes more from how other standards outside of Java come about. To me, the JCP often is done in a backwards sort of manner where the spec is defined before any real code has been written. EJB is a good example of a spec that was very complicated and had to go through several painful revisions (Ask Java devs about EJB 2), before we started to see a push to make the spec simpler (EJB3). This sort of spec first code later attitude seems to be challenged more and more by the rough code, general consensus crowd. A couple of good examples that come to mind are Spring and OSGi which both came about outside of the JCP and both now have JCP experience in different ways.
Rod Johnson of Spring also believes in rough code, general consensus when he wrote about his and Spring Source's approach to the JCP. This move towards proving technologies and techniques before submitting a JSR is something we will see happen more and more as Java progresses. JSR330 - Dependency Injection for Java, is a good example of this happening. JSR330 combines the knowledge learned from Spring and Guice to define some basic annotations for Dependency Injection in Java.
In the end, I'm glad to see fewer JSRs being submitted and giving more time for techniques and technologies to adapt and mature before working through the JCP to define a standard. Now all we need to do is get more people to experiment with closures and reified Generics...
I've been following the long saga between The Apache Software Foundation and the Sun over Apache Harmony for a while now and there are definitely problems with the JCP that need to be resolved. Colebourne's post shows the declining trend in numbers of JSRs submitted to the JCP and brings up the question as to whether this is a sign of the times for the JCP or something normal for a maturing language such as Java.
I think the answer is a bit of both. As Colebourne points out, his chart only includes new JSRs and not ones that are in maintenance mode or being updated, such as Java EE 6 for example (which connects about 30 other JSRs, most of which are not new). Since Java is a large platform that has been around for quite some time now that seems very normal to me from a mature language.
The other part I'm starting to see comes more from how other standards outside of Java come about. To me, the JCP often is done in a backwards sort of manner where the spec is defined before any real code has been written. EJB is a good example of a spec that was very complicated and had to go through several painful revisions (Ask Java devs about EJB 2), before we started to see a push to make the spec simpler (EJB3). This sort of spec first code later attitude seems to be challenged more and more by the rough code, general consensus crowd. A couple of good examples that come to mind are Spring and OSGi which both came about outside of the JCP and both now have JCP experience in different ways.
Rod Johnson of Spring also believes in rough code, general consensus when he wrote about his and Spring Source's approach to the JCP. This move towards proving technologies and techniques before submitting a JSR is something we will see happen more and more as Java progresses. JSR330 - Dependency Injection for Java, is a good example of this happening. JSR330 combines the knowledge learned from Spring and Guice to define some basic annotations for Dependency Injection in Java.
In the end, I'm glad to see fewer JSRs being submitted and giving more time for techniques and technologies to adapt and mature before working through the JCP to define a standard. Now all we need to do is get more people to experiment with closures and reified Generics...
Thursday, January 29, 2009
Impressive = KeyJnote
I'm glad to see that KeyJNote has returned as Impressive. A while ago it seemed like KeyJNote had fallen off the face of the earth, but now its back with a new name. I'll have to try it out some more now that I can find it again.
Monday, January 12, 2009
Ubuntu on a Stick
I got a Patriot Xporter 32Gb thumb drive for Christmas and I finally got around to installing Ubuntu 8.10 on it. This was my first experience with installing any Linux distro on a thumb drive and booting from USB so it has been an interesting experience, here is what I encountered when trying to get my thumb drive working.
8.10 USB Startup Disk Creator
Of course, the first place I started was the USB Startup Disk Creator, which has been available since Ubuntu 8.04. The process is simple:
- Popped in my USB drive.
- Went to System>Administration>Create a USB Startup Disk
- Selected my USB drive and selected the option "Stored in reserved extra space"
- Adjusted the extra space slider to the full 32 Gb
- Clicked "Make startup disk"
Easy.... and slow. It took a pretty good amount of time for the drive to be completely setup. Nothing too bad, but enough to get up and find something else to do for a while. Unfortunately something went wrong in the process or my laptop is messed up (which it could possibly be). When I restarted my computer and selected the USB drive as the primary boot device, I would only get that the drive was corrupted. I tried to troubleshoot the problem and also tried to recreate the startup disk to no avail.
I'm not sure what happened, but I'm pretty sure its something on my end (perhaps the USB drive) and not that of the USB Startup Disk creator. Fortunately, I found an alternative method that I did get working for me.
UNetbootin to the rescue
While searching around for clues to my problems from the startup disk creator, I ran across UNetbootin so I decided I'd give it a try. Here are the steps I took with UNetbootin:
- Downloaded and started UNetboontin on my XP laptop.
- Downloaded the Ubuntu 8.10 iso - (I actually already had an iso on the laptop, doh)
- Selected my Distro - Ubuntu 8.10
- Checked Disk Image and pointed UNetboontin to the Intrepid iso
- Selected my USB drive as the device to be installed to
- Pressed ok and sat back
The UNetbootin process was extremely easy to follow and it seemed to me that it took less time to format the disk and get the USB drive set up. After I finished, I rebooted XP and switched the boot device to USB again. This time it dropped right into the Ubuntu live menu where I started Ubuntu right up. Success! Both methods were extremely easy to use and weren't very time consuming.
Ubuntu from a thumb drive
Ubuntu takes quite a while to boot up from my thumb drive, but once it does its very responsive and quite fun to work with. Unfortunately you don't want to do too much disk intensive work since it seems like the writes are a little on the slow side, but bearable. Its been really fun to set up my own portable Ubuntu install with a decent amount of storage. In the coming months I'll try running the portable install on several computers to get a feel for how actually portable it is. For now though, I've been very pleased with the results and I look forward to using this as my portable Linux haven from now on.
This also has prompted me to consider picking up a couple 4 Gb thumb drives so I won't have to burn another install disk. I hate having so many piles of CD-Rs with different distros on it when I could just slap it on a thumb drive and go. (unless I can't boot from USB, but thats besides the point) So congrats to the Ubuntu team on a lovely tool as well as the Fedora team who helped motivate the Ubuntu team to improve their USB install tools as well.
Subscribe to:
Posts (Atom)