tag:blogger.com,1999:blog-78689509626798655022024-03-08T06:42:08.084-05:00Colin's DevlogThoughts on software development, technology, etc.Anonymoushttp://www.blogger.com/profile/15553994884731312441noreply@blogger.comBlogger10125tag:blogger.com,1999:blog-7868950962679865502.post-23606266220260652262011-11-12T12:53:00.001-05:002011-11-12T16:45:14.323-05:00Lambdas in Java: Playing with the snapshot binary<p>The <a href="http://jdk8.java.net/lambda/">first binary snapshots</a> of the Project Lambda repository were made available yesterday. I hadn't bothered to check out and build the code before now, but with only having to download the snapshot I decided to give it a try. I'd been following the mailing list and looking at the code changes to the JDK libraries, so I more or less knew what to expect.</p>
<p>In general, things worked nicely. While I wasn't a big fan of it at first, I do like how concise the new syntax is. It's similar to the C# syntax:</p>
<pre><code>people.filter(p -> p.getAge() < 50)
.map(p -> p.getFirstName() + " " + p.getLastName())
.forEach(n -> { System.out.println(n); });</code></pre>
<p>It's pretty much what you'd expect, and obviously nothing revolutionary... just long overdue in my opinion. What I'm really excited about is the improvements to APIs (and new APIs) that concise lambda expressions will allow in Java. I experimented with just a few examples, including:</p>
<ul>
<li>A table model that uses a map function to derive column values from objects.</li>
<li>A logging API that can take a <code>Supplier</code> for the message so that it only builds the message if needed.</li>
<li>A version of Guava's <code>Optional</code> that has a <code>map</code> function. Far too clunky to be very useful with anonymous inner classes, very nice with a concise lambda expression:</li>
<li>A framework for async tasks with callbacks based on Guava's <code>ListenableFuture</code> code that I've been playing with. It's so much nicer when there's so little syntactic overhead for both submitting tasks (since lambdas can be used for <code>Runnable</code> and <code>Callable</code>) and adding callbacks (since they can be SAM types too).</li>
</ul>
<p>Extension methods should also be a huge benefit. While it could be considered unfortunate that they don't allow you to add methods to others' APIs, I think that's a reasonable decision for Java. Giving API authors the ability to extend interfaces will allow APIs to evolve over time in ways they couldn't before.</p>
<p>There were a couple issues I noticed, but they weren't a big deal and are to be expected with something that's very much in progress.</p>
<p>Extension methods only work for JDK classes out of the box because currently a bytecode weaving tool is used to simulate VM support for extension methods (which isn't there yet). That tool was run as part of the snapshot build, but has to be run separately on any other classes that you want to support extension methods. For example, an <code>AbstractMethodError</code> is thrown if you try to call <code>filter</code> on Guava's <code>ImmutableList</code>... the compiler knows that you should be able to call it since <code>filter</code> is defined on <code>Iterable</code>, but without the VM support or having run the weaver for <code>ImmutableList</code>, it fails at runtime. (Mike Duigou explains how to use the weaver <a href="http://mail.openjdk.java.net/pipermail/lambda-dev/2011-November/004147.html">here</a>.)</p>
<p>Support for method references seems kind of shaky. The compiler threw an exception in one situation where I tried to use a method reference and I got compile errors in a number of other situations where I thought a method reference should work. In some other situations, they worked. A final syntax hasn't been decided on for method references, so I imagine support for them just isn't as far along.</p>
<p>There were some unfortunate overload resolution shortcomings. For example, neither of the following statements compile:</p>
<pre><code>Comparator<String> c = Comparators.comparing(s -> s.length());
Comparator<String> c = Comparators.comparing(
(String s) -> s.length());</code></pre>
<p>You have to write one of the following, so it know which kind of <code>Mapper</code> you want the lambda to be:</p>
<pre><code>Comparator<String> c = Comparators.<String, Integer>comparing(
s -> s.length()); // Mapper<String, Integer>
Comparator<String> c = Comparators.comparing(
(IntMapper<String>) s -> s.length()); // IntMapper<String></code></pre>
<p>I hope it will be possible to change the resolution to choose the most specific interface (in this case <code>IntMapper<String></code>) so I don't have to specify it unless I want to.</p>
<p>Anyway, it was fun to be able to actually write and run code using lambda expressions in Java. Between Project Lambda and JSR-310 (the new date/time API), I'm really looking forward to JDK 8... too bad it isn't coming until 2013!</p>Anonymoushttp://www.blogger.com/profile/15553994884731312441noreply@blogger.com1tag:blogger.com,1999:blog-7868950962679865502.post-23330783016055041612011-06-20T17:31:00.001-04:002011-06-20T17:31:03.930-04:00Using librariesI occasionally get flak for recommending Guava as a solution on relatively simple questions on StackOverflow. The argument generally goes: "this is so easy, don't add a library just for that!". The key phrase there is "just for that": it seems that some people on StackOverflow tend to take the viewpoint that whatever is being asked in the question is all the person who asked will need to do and that as such the only valid answer is some standalone code they can copy and paste in. I don't believe that a whole library is worth it to save yourself from writing one 4-line method... I just believe code doesn't exist in isolation and that in almost any project that's more than a few classes, Guava will be more than worth its weight.<br />
<br />
The point of Guava is that it makes a lot of things easier, from fairly easy things that take several lines of code (but should just take one) to very hard things that would be easy to get wrong. In aggregate, using its facilities instead of writing extra code yourself can make your application clearer and more maintainable. There's also the benefit that people who have used the library before will know where to look for things instead of having to figure out what class in your project (if any) you copy/pasted some certain utility method into.<br />
<br />
I also believe that it's up to the person who asked the question to evaluate whether they want to add a library or not. Someone almost always posts an alternative answer that does not use a library, so that option is generally going to be on the table. My hope is that they'll say "oh, nice that someone has made something that fixes this little pain point for me", take a look at what else it offers and recognize the value it'll provide them. I hope this because I genuinely believe they'll be better off if they do.<br />
<br />
I'm aware that there are various concerns such as company policy that can get in the way of using a 3rd party library and that opinions differ on what libraries are good to use, but in general I think answers that make use of libraries are perfectly valid even when they aren't necessarily a big savings over writing the code yourself for the problem at hand.Anonymoushttp://www.blogger.com/profile/15553994884731312441noreply@blogger.com1tag:blogger.com,1999:blog-7868950962679865502.post-28020399068689995362011-04-07T18:42:00.000-04:002011-04-07T18:42:23.092-04:00Lambdas in Java: constructor references<p>One thing I'm extremely excited about is the addition of support for lambda expressions in JDK 8. I've been following the Project Lambda mailing list since its creation and watching as things have evolved (and as it slipped from JDK 7, sadly... though there really wasn't time for it). Anyway, since I'm constantly thinking "Gahhh! If only Java had lambdas already!" when I'm working, I thought I should do some posts talking about what I'm looking forward to. Most of them will probably involve <a href="http://code.google.com/p/guava-libraries/">Guava</a> (since it's one of my favorite things in Java) and how things you can do currently with it will be easier and read nicer using lambdas.
</p>
<p>Today, I want to talk about constructor references! Basic support for them <a href="http://hg.openjdk.java.net/lambda/lambda/langtools/rev/9a616df38d88">was added</a> to the lambda repository of OpenJDK back in January.
</p>
<p>A constructor reference is, as its name implies, a reference to a class constructor. Creating such a reference gives you an object implementing some interface and having a single method that, when called, will call the constructor and return the new instance that is created. For a simple example of how constructor references can help make code that's currently verbose nice and simple, consider the following code:
</p>
<noscript><pre>
Multimap<String, String> multimap = Multimaps.newMultimap(
new TreeMap<String, Collection<String>>(),
new Supplier<List<String>>() {
@Override public List<String> get() {
return new ArrayList<String>();
}
});
</pre></noscript>
<script src="https://gist.github.com/908797.js?file=gistfile1.java"></script>
<p>This code creates a <code>Multimap</code> sorted by keys but with unsorted <code>ArrayList</code>s holding values. One thing stands out here: the <code>Supplier</code>. That's a lot of code just to say "I want to make an <code>ArrayList</code> for each collection". But there isn't really any better way to do that in Java. Now take a look at how a constructor reference improves this:
</p>
<noscript><pre>
Multimap<String, String> multimap = Multimaps.newMultimap(
new TreeMap<String, Collection<String>>(), ArrayList<String>#new);
</pre></noscript>
<script src="https://gist.github.com/908797.js?file=gistfile2.txt"></script>
<p>The whole bulky <code>Supplier</code> from the first example has been replaced with <code>ArrayList<String>#new</code>. Just that! The reference to the no-arg constructor for <code>ArrayList</code> will be translated to a <code>Supplier<ArrayList<String>></code> since it has a compatible method signature (no arguments and returns an <code>ArrayList<String></code>). This is a <em>huge</em> improvement! Not only does it cut out 2/3 of the lines of code here (and a lot of ugly indenting, etc.), it's much clearer what we're doing.
</p>
<p>What if you want to specify the initial capacity for the lists that are created? This is just as easy: use <code>ArrayList<String>#new(100)</code> instead. This will call the constructor that takes an <code>int</code> argument each time, passing the value <code>100</code>.
</p>
<p>Of course, even without constructor references all this would be relatively easy using lambda expressions: <code>ArrayList<String>#new</code> would instead be something like:
</p>
<pre><code>#{ -> new ArrayList<String>() }</code></pre>
<p>It's nice to see constructors are getting the same treatment methods are, though.
</p>
<p>As a side note, boy do I ever wish that I could use markdown on this blog. If writing a nicely formatted blog post were as easy as writing a StackOverflow answer... well, maybe I'd do it a little more often!</p>Anonymoushttp://www.blogger.com/profile/15553994884731312441noreply@blogger.com1tag:blogger.com,1999:blog-7868950962679865502.post-84915268616899341042011-02-16T00:49:00.003-05:002011-02-16T02:38:52.854-05:00Deploying documentation to GitHub pages with Jenkins / Hudson<p><a href="http://pages.github.com/">GitHub Pages</a> is a neat feature of GitHub that allows you to serve static files by using a special <code>gh-pages</code> branch in a repository. Having got Jenkins set up to build my <a href="https://github.com/cgdecker/jdbc-persist">jdbc-persist</a> project, I thought it would be neat to set up something to take the Javadoc generated during a build and automatically push it to the <code>gh-pages</code> branch when the build finishes.</p>
<p>My project uses Maven for building, and I didn't see any way to have the same job that builds the project handle pushing the documentation on a separate branch, so I set up a second job (which I called <code>jdbc-persist-site</code>) to do that.</p>
<p>The process isn't terribly elegant. The first job uses the Maven <code>site:site</code> goal to generate both Javadoc and a whole Maven project site. The second project first pulls my <code>gh-pages</code> branch. It then runs the following batch script (wouldn't be much different as a .sh script):</p>
<noscript><pre>del *
cp -r ../../jdbc-persist/site/* .
git add .
git add -u
git commit -m "Auto-update site"</pre></noscript>
<script src="https://gist.github.com/828921.js?file=gistfile1.txt"></script>
<p>This basically just grabs the generated site from the other job manually and overwrites the previous version of the files. I actually had to split the three git commands into 3 separate batch file steps in Jenkins because a single script would stop after just 1 git call.</p>
<p>The final step was to push the new commit to <code>gh-pages</code> so that the updated files would show up. This was a simple matter of selecting the Git Publisher post-build action and telling it to publish to the <code>gh-pages</code> branch on <code>origin</code>. I also set up a trigger to run the <code>jdbc-persist-site</code> job after any successful <code>jdbc-persist</code> build, ensuring that any changes I make are automatically reflected on the site each time.</p>
<p>I find an approach like this to be far better than the approach of storing generated Javadoc files in the same branch as the source code the way a number of projects I like (<a href="http://code.google.com/p/guava-libraries">Guava</a> and <a href="http://code.google.com/p/google-guice">Guice</a> for example) do. Directories containing artifacts like Javadoc that can be derived from the source clutter up the project structure, clutter up commit history with changes to derived files and add to the volume of files that someone checking out the project has to download. I think the ability to do this sort of thing easily speaks well for the ease and power of Git's branching model and for GitHub's awesome features!</p>Anonymoushttp://www.blogger.com/profile/15553994884731312441noreply@blogger.com1tag:blogger.com,1999:blog-7868950962679865502.post-83337224346010952132011-02-15T00:52:00.011-05:002011-02-15T12:24:52.831-05:00Git clone error on Jenkins/Hudson on WindowsRecently I set up a new instance of Jenkins (formerly Hudson) running on my Windows 7 desktop computer. I tried to set up a job that would pull from a GitHub repository and do a build but (like every other time I've tried this) was foiled by the job simply hanging at the step where it tries to clone or fetch from GitHub. Cancelling the job leads to the following errors in the console output:
<p/>
<script src="https://gist.github.com/827147.js?file=gistfile1.txt"></script>
<noscript><pre>Started by user cgdecker
Checkout:workspace / E:\Colin\.hudson\jobs\temp\workspace - hudson.remoting.LocalChannel@692769e1
Using strategy: Default
Checkout:workspace / E:\Colin\.hudson\jobs\temp\workspace - hudson.remoting.LocalChannel@692769e1
GitAPI created
Cloning the remote Git repository
Cloning repository origin
$ git clone -o origin git@github.com:cgdecker/jdbc-persist.git E:\Colin\.hudson\jobs\temp\workspace
ERROR: Error cloning remote repo 'origin' : Could not clone git@github.com:cgdecker/jdbc-persist.git
ERROR: Cause: Error performing git clone -o origin git@github.com:cgdecker/jdbc-persist.git E:\Colin\.hudson\jobs\temp\workspace
null
Trying next repository
ERROR: Could not clone repository
FATAL: Could not clone
hudson.plugins.git.GitException: Could not clone
at hudson.plugins.git.GitSCM$2.invoke(GitSCM.java:809)
at hudson.plugins.git.GitSCM$2.invoke(GitSCM.java:740)
at hudson.FilePath.act(FilePath.java:756)
at hudson.FilePath.act(FilePath.java:738)
at hudson.plugins.git.GitSCM.checkout(GitSCM.java:740)
at hudson.model.AbstractProject.checkout(AbstractProject.java:1171)
at hudson.model.AbstractBuild$AbstractRunner.checkout(AbstractBuild.java:499)
at hudson.model.AbstractBuild$AbstractRunner.run(AbstractBuild.java:415)
at hudson.model.Run.run(Run.java:1362)
at hudson.maven.MavenModuleSetBuild.run(MavenModuleSetBuild.java:405)
at hudson.model.ResourceController.execute(ResourceController.java:88)
at hudson.model.Executor.run(Executor.java:145)</pre></noscript>
<p/>
First, I tried the usual suspects:
<ul>
<li>Ensuring that Jenkins was running as the correct user.</li>
<li>Ensuring that the user's <code>.ssh</code> directory and keys were in place and checked out.</li>
<li>Trying the full path to <code>git.exe</code> in Git's bin directory rather than just using <code>git</code> as the path.
</ul>
<p>I did a search for the error, but as in the past it turned up no solutions that actually fixed the problem for me. I then tried running a job that just executed a Windows batch command to run <code>git clone</code> on the same repository... which worked fine!</p>
<h3>The solution</h3>
<p>Double-checking things, I noticed that my PATH contained two directories for my Git installation (msysgit): one for <code>Git/bin</code> and another for <code>Git/cmd</code>, which I hadn't been aware of before. Looking in <code>Git/cmd</code>, I noticed that it contained a file <code>git.cmd</code> which appeared to be some kind of script wrapping <code>git.exe</code>. So, I went into the Jenkins configuration and changed the path to the git executable to <code>git.cmd</code>. And that fixed everything!</p>
<p>Based on what I've seen when searching for this error, it seems like there are quite a few potential causes for it. But this is what worked for me in my situation and I haven't seen this solution elsewhere, so I thought I'd write it down... if nothing else to help me remember if it happens again.</p>Anonymoushttp://www.blogger.com/profile/15553994884731312441noreply@blogger.com8tag:blogger.com,1999:blog-7868950962679865502.post-49408605989136887802010-06-18T01:09:00.003-04:002011-02-15T11:30:16.306-05:00Property interfaces and Guava functional programmingSomething that I’ve been thinking about lately is how I can make it easier to use <a href="http://code.google.com/p/guava-libraries/">Guava</a>’s methods that operate on <a href="http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/base/Function.html">Function</a>s, <a href="http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/base/Predicate.html">Predicate</a>s, etc.
<p>
One simple use for <code>Function</code>s is to get properties of objects, allowing you to (among other things) create a transformed view of a collection containing a certain property from each element. For example, transforming a list of <code>Person</code> objects to a <code>String</code> collection of names. Any time you want to do something with a collection of objects based on a certain property of those objects, this is useful.
<p>
However, it's rather ugly and awkward to have to create an anonymous inner class inline when calling a method that uses a <code>Function</code>. While you can create <code>static final</code> instances of such functions and methods that return instances of functions, with many classes you could end up with many such instances and methods. One good way to reduce the number of <code>Function</code> objects you need to create and make it easy to work with certain common properties (such as IDs, names, etc.) on many objects is to create interfaces that each expose a single such property:</p>
<noscript><pre class="brush: java">
interface HasId {
Long getId();
}
</pre></noscript>
<script src="https://gist.github.com/827748.js?file=HasId.java"></script>
<p>Not only does this help add consistency to your classes, it allows you to collect behavior that can work on any type of object that has the property the interface exposes. I'd probably name such classes as the plural of the property name ("Ids" and "Names", for example).</p>
<noscript><pre class="brush: java">
class Ids {
private Ids() {}
public static final Function<HasId, Long> GET =
new Function<HasId, Long>() {
public Long apply(HasId hasId) {
return hasId.getId();
}
};
public static Iterable<Long> of(
Iterable<? extends HasId> items) {
return Iterables.transform(items, GET);
}
}</pre></noscript>
<script src="https://gist.github.com/827748.js?file=Ids.java"></script>
<p>This makes working with the IDs of a list of things with IDs as easy as possible:</p>
<noscript><pre class="brush: java">
List<Person> people = ...
for(Long id : Ids.of(people)) { ... }
</pre></noscript>
<script src="https://gist.github.com/827748.js?file=IterateIds.java"></script>
<p>The <code>GET</code> function is exposed to allow its use for anything you might want a function for, not just <code>tranform</code>. For example, with a <code>HasName</code> interface and <code>Names</code> class similar to the code for IDs, I could do something like this:</p>
<noscript><pre class="brush: java">
List<Person> people = ...
Iterable<Person> bobs = filter(people, compose(equalTo("Bob"),
Names.GET));
</pre></noscript>
<script src="https://gist.github.com/827748.js?file=FilterByName.java"></script>
<p>This would of course filter a list of people to an iterable that only includes people with the name Bob. It uses static imports (because they make this stuff read a lot nicer), and the methods are:</p>
<ul>
<li><a href="http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Iterables.html#filter%28java.lang.Iterable,%20com.google.common.base.Predicate%29">Iterables.filter(Iterable,Predicate)</a></li>
<li><a href="http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/base/Predicates.html#compose%28com.google.common.base.Predicate,%20com.google.common.base.Function%29">Predicates.compose(Predicate,Function)</a></li>
<li><a href="http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/base/Predicates.html#equalTo%28T%29">Predicates.equalTo(T)</a></li>
</ul>
<p>I think this approach can make working with the properties of objects using <code>Function</code>s a lot easier and cleaner, while also encouraging more consistency between classes in general, which is nice.</p>Anonymoushttp://www.blogger.com/profile/15553994884731312441noreply@blogger.com2tag:blogger.com,1999:blog-7868950962679865502.post-3795120743039581302010-03-25T22:06:00.001-04:002011-02-15T11:24:19.424-05:00Get your UI out of my logic<noscript><pre class="brush: java">
public enum Type {
Select,
TypeA,
TypeB,
TypeC;
}</pre></noscript>
<script src="https://gist.github.com/827737.js?file=yuck.java"></script>
<p>I really don't like seeing something like this used in a domain object.</p>
<p>I've also seen a list of objects retrieved from the database and put into an Object array with "Select" as array[0] and the rest of the objects being actual objects someone might care about. Let's just have everyone remember what type of objects are in this array, and they should also remember that the first element isn't one of those!</p>
<p>I can't imagine what people find so hard about producing a new list or whatever to base their combo box model on at the time that the combo box is actually created. Furthermore, with something like the <code>enum</code> above, the enum constants use lowercase letters because it'll look nicer when they're rendered in the UI using the default <code>toString()</code>. The use of <code>toString()</code> to produce the text for the UI in general bothers me. I want it to produce text that's helpful to me in error messages... use some other means for rendering it to users.</p>
<p>I guess what I want to say is: keep user interface concerns where they belong, near the user interface!</p>Anonymoushttp://www.blogger.com/profile/15553994884731312441noreply@blogger.com0tag:blogger.com,1999:blog-7868950962679865502.post-46095716494385524912010-01-22T18:38:00.000-05:002010-01-22T18:38:59.737-05:00What's the issue with @Inject?<p>Reading Uncle Bob's recent <a href="http://blog.objectmentor.com/articles/2010/01/17/dependency-injection-inversion">post about dependency injection frameworks</a>, I noticed that quite a few people seemed to be treating the use of <a href='http://code.google.com/p/google-guice/'>Guice</a>'s <code>@Inject</code> annotation in their application code as a reason to prefer other DI frameworks to Guice. For the most part, none of them provided any explanation for why using the annotation in application code was a problem other than "I don't like it". Even ignoring the fact that <a href='http://code.google.com/p/atinject/'>JSR-330</a> standardizes the only annotations and the one interface from Guice that are used in application code and will be usable with Guice 2.1, I find it difficult to understand these points of view. What's the issue people have with it?</p>
<h3>Why it's good</h3>
<p><code>@Inject</code> is just one annotation that, in a typical concrete class, will be used on one constructor and MAYBE a couple setters. It allows dependencies to be injected without any explicit configuration of the Spring XML form while retaining <b>safe</b> and predictable behavior by ensuring that injections always take place using the exact constructors and methods you want to use. It saves you from ever having to specify anything using strings, making it possible to refactor and rename classes and methods without any risk of breaking your DI configuration... I think this is an extremely important point. It generally doesn't allow anything <b>unexpected</b> to happen.<p>
<h3>Tied to the framework?</h3>
<p>I feel like the knee-jerk reaction to using <code>@Inject</code> in classes is that by doing that, you're somehow tying yourself to Guice. As Uncle Bob put it,
<blockquote>I don’t want to write a <i>Guice</i> application. Guice is a framework, and I don’t want framework code smeared all through my application. [...] I don’t want to have <code>@Inject</code> attributes everywhere [...]</blockquote>
I understand that when he says this, Uncle Bob is arguing against using DI frameworks in general. Ignoring that argument for now and accepting that DI frameworks are worth using, the fact is that if you're using a DI framework, you are tying yourself to it. It's how your application is configured, unless you're doing all the work to create an alternate way of wiring the application together in which case... why? If you choose to switch to another DI framework or stop using a DI framework entirely (and how likely are either of these, really?) it is going to involve some work to remove the existing configuration and write the new configuration. And removing a bunch of <code>@Inject</code> annotations would be an absolutely trivial part of that.
<h3>Annotations are not code</h3>
<p>I think it's important to note that annotations are not code. By themselves, they do nothing. You can use a class even without the annotations on its elements available on the classpath. When writing tests, you can completely ignore them. Guice's annotations will also never be in the <i>body</i> of your code, meaning you should generally be able to ignore them when reasoning about how a class behaves. One comment I read (from a Spring XML user) stated that the commenter considered annotations "just as bad" as code and likened the <code>@Inject</code> annotation to providing your classes with the <code>ApplicationContext</code> (Spring's central container interface). This is, of course, way off base. Providing programmatic access to the central container ties the code itself to the DI framework. The class can then use the framework's code directly to get access to any object it wants, anywhere in its code. Testing the class would require configuring a container and looking through the class to see what needs to be in it. The framework becomes a Service Locator framework. The <code>@Inject</code> annotation imposes no such thing.</p>
<p>In general, I think the benefits provided by Guice and the configuration safety provided by the use of <code>@Inject</code> <b>far</b> outweigh the at most minor annoyance of placing an annotation or so per injectable class. In future posts I'd like to talk more about what I like about dependency injection and Guice.</p>Anonymoushttp://www.blogger.com/profile/15553994884731312441noreply@blogger.com3tag:blogger.com,1999:blog-7868950962679865502.post-58612646890463153852009-07-10T02:06:00.000-04:002010-01-21T13:08:25.018-05:00Git and CVSIn my <a href="http://blog.cgdecker.com/2009/07/learning-git.html">last post</a> I talked a little about my experience starting to learn to use Git. Now I'm going to talk about what I'm doing with it currently in an environment where Git can't be used as the end-to-end version control system (at least not immediately).<br />
<h4>The Situation</h4>At work we're using CVS for a legacy project that I'm working on. It's been around a while and the practices with it are pretty set. Branches are used for release versions of the product and that's about it. I tend to have a feature or two I'm working on and I also occasionally do something experimental. The trouble is, getting changes related to separate things mixed together can make it confusing to know what needs to be committed and what doesn't when it comes time to commit something (committing early and often would help with this, but it's not quite how things are done). Especially problematic would be if changes related to different things affected the same file.<br />
<br />
To deal with this, I'd sometimes check out a separate copy of the project into another directory and work on something specific there, but this wasn't very efficient. I'm programming in Java using Eclipse, and in addition to the issue of keeping track of multiple complete copies of the project, I'd have to switch workspaces or open up another copy of Eclipse to work with those copies. This wasn't very efficient.<br />
<h4>The Solution</h4>When I started looking into Git and experimenting with it, I realized that I could probably use it locally with a totally different VCS acting as the central repository. Git stores all its data in a single folder in the root of the working directory, which means that its files aren't mixed into your entire directory structure the way they are with CVS and its CVS subdirectories in every directory.<br />
<br />
Here's the process I used to get this project set up for work with Git:<br />
<ul><li>Check out a clean copy of the project into a new directory to use.</li>
<li>Get the environment all set up for normal use in Eclipse.</li>
<li>Do <code>git init</code> to create the Git repository at the root of the project.</li>
<li>Create and set the .gitignore file, having it ignore compiled code output folders, among other things. <strong>(Note: It should also ignore all CVS folders.)</strong></li>
<li><code>git add .</code> everything that isn't ignored, making sure you aren't getting anything you don't want to.</li>
<li>Do the initial <code>git commit</code>.</li>
<li>From there, use Git normally... create a development branch, and branches off that for features, experiments, etc.</li>
<li>When you're ready to commit something to CVS, merge the changes all the way down to the master branch and commit in CVS.</li>
</ul>When I switch branches, I just refresh the project in Eclipse and it immediately reflects the branch I'm now on. Since the files that exist may differ between branches, I also like to use tasks in Mylyn. I have tasks that are specific to whatever I'm doing on a specific branch, and I activate them while working on them. I'd done a little of that before, but it's even more useful in this situation. If I'm working on some files and need to switch to another branch that doesn't have them, I just deactivate the task and the editor tabs go away. I switch branches, do whatever I need, and then when I switch back and activate the task. Despite the fact that the files ceased to exist on the files system for a while, when the task is reactivated the files are right back there like before!<br />
<br />
This approach has made it far easier and more fun to work on multiple separate things at once, and it's easy to do even though the central repository is the ancient CVS! Thanks for being awesome, Git!<br />
<br />
<strong>Update:</strong><br />
<br />
How you interact with CVS when doing this is important. First, the .gitignore file should be set to ignore all CVS folders! You don't want changes to the files in the CVS folders to have to be committed to your Git repository. You want to ignore the fact that you're also using CVS as much as possible. Given that, you should also only ever update from CVS or commit to CVS from your master branch! Things can get really weird if you update or commit in a branch you've created.Anonymoushttp://www.blogger.com/profile/15553994884731312441noreply@blogger.com1tag:blogger.com,1999:blog-7868950962679865502.post-62066671888057397082009-07-08T04:04:00.001-04:002010-01-20T21:32:06.502-05:00Learning GitOne thing that I've been realizing more and more recently is the importance of keeping up with advancements in developer tools. I'm a strong believer that if you aren't using the best tools available for the job you're doing, you aren't being as effective as you could be, regardless of how much effort you put in to it. Plus, as a <a href="http://blogoscoped.com/archive/2005-08-24-n14.html" target="_blank">lazy programmer</a> I certainly don't want to put more effort in to something when a better tool could save me from that.<br />
<br />
Up until recently, I'd only used CVS and Subversion for source control... CVS at work and a little in college, and Subversion at home because I knew it was more recent than CVS. As I started to pay more attention to what I was seeing around the web on blogs and <a href="http://news.ycombinator.com/" target="_blank">Hacker News</a>, I began to notice a lot of positive references to <a href="http://git-scm.com/" target="_blank">Git</a>. It seemed a little intimidating to me, at first... largely command line based, with no full-featured shell integration like Tortoise for Windows? I didn't know about that... I like just right-clicking on files for diffs, commits, etc.<br />
<br />
Tales of the wonders of branching in Git were probably what brought me around to finally try it out this weekend... well, that and <a href="https://github.com/" target="_blank">GitHub</a>, which is awesome. Anyway, on sitting down and starting to learn it I discovered that it really wasn't hard at all to pick up. A quick <code>git init</code>, <code>git add .</code> and <code>git commit</code> and I had a small existing project that I hadn't put in version control yet committed to a Git repository. And from there, pushing it to a repo on GitHub was incredibly easy as well. I then spent some time experimenting with branching and merging and all that fun stuff. I'll admit that I certainly still don't know all the intricacies of it, but the basic process was as easy and wonderful and rainbows as advertised.<br />
<br />
One of the things I <em>really love</em> about Git is the fact that it uses a local repository in addition to a remote one (and that only if you want/need it to). Branches are such a great way of keeping logically separate units of work... well, separate, and that includes experimental changes. It's nice to be able to have experimental branches without them needing to be stored in the central repository that everyone on a project uses. Also great is the concept of the working directory, and how easily and quickly the files in it change as you change branches. Having one directory you can work from with all the different branches of your project has many advantages. I think I'll get in to that and some details of how I'm starting to make use of Git at work in my next post, which will probably be related to using Git locally with a central CVS repository.Anonymoushttp://www.blogger.com/profile/15553994884731312441noreply@blogger.com0