I'm blogging about programming, but ... hey look over there - it's something shiny!
Saturday, September 07, 2019
A Generic Funeral Brochure Template in Google Documents
The template document is here. (Thanks to wikipedia for the content text).
It consists of a two column table on each page with the correct dimensions to print well.
The pdf created from Google Docs is here.
If you set your printer for double-sided printing it will print it out like this:
Tuesday, September 03, 2019
In Windows 10 the Desktop Window Manager is using 100% of the GPU
Saturday, July 13, 2019
Self referencing loop detected for property 'Object' with type 'Castle.Proxies.IServiceContextProxy
Message="Self referencing loop detected for property 'Object' with type 'Castle.Proxies.IServiceContextProxy..."
It happens when JSON is trying to serialize an object that it thinks has a pointer to itself and could create an infinite loop - although in your code it may not be infinite, but JSON doesn't know that. It's just trying to protect you.
One way to fix this is to replace the Mock object with real fake object.
Saturday, June 29, 2019
The Most Underrated Wonder of the Ancient World - Obelisks
My daughter and me under Cleopatra's Needle at the Met in New York
- Twenty Eight Egyptian obelisks remain standing today.
- They are built from a single piece of rock.
- The Egyptians did not have iron tools, so it is thought they pounded the granite with heavy dolerate rocks - one of the few things harder than granite.
- An army of workers would have had to labor "an infinity of hours" to create one. If a crack were found in the rock during work, the monolith would be abandoned and work started on another site.
- Obelisks could be 100 feet tall and weigh 400 tons.
- Moving them was tricky, because the granite would crack easily if not properly supported. Stone is great in compression, but weak in tension.
- In 37 AD Gaius Caligula ordered an Egyptian obelisk that was already 1800 years old to be moved to Rome. It was 25 meters tall with a base of 8 meters and weighed one million pounds and made of pink granite. It remained standing in Rome for 1500 years.
- The end of the Middle Ages.
The pope ordered the obelisk moved to the center of St. Peter's square. On September 10, 1586 the obelisk was moved by 907 men, 75 horses and 40 cranes.
No obelisk had been moved for over a thousand years, and the people of 1586 thought they had at last equalled their Roman ancestors . The fact that they had moved the obelisk only a few hundred meters, instead of from across the Mediterranean did not matter - a new age of technology and engineering was dawning. Some historians mark this engineering marvel as the end of the Middle Ages and the beginning of the Renaissance.
As it looks now:
Tuesday, May 21, 2019
Interview Questions for Older Relatives for Genealogy Research
https://www.deseretnews.com/article/865595932/Genealogy-150-questions-to-ask-family-members-about-their-lives.html
http://sites.rootsweb.com/~ohlths/interview2.htm
https://www.thoughtco.com/fifty-questions-for-family-history-interviews-1420705
If your parents, or grandparents, are still alive ask them some of these questions and record your conversation on your phone. They will be gone before you know it.
You can see more photos about the Fincher clan at https://www.fincher.org/fincher/index.shtml
Tuesday, April 16, 2019
Agile Austin - Why 76% Of Organizations Are Failing At Agile
Why 76% Of Organizations Are Failing At Agile
David Hawks from AgileVelocity.com gave a great presentation to 50 Agilists at Agile Austin this week.
He used an interactive poll from PollEveryWhere.com which was a nice touch, so the audience could vote in real time on a question and we could see the results in a bar chart.
Four phases of change:
1. "Status Quo"
2. "Chaos and Resistance" When we introduce change the process always get worse.
3. "Integration and Practice" is next in which things slowly get better.
4. "New Status Quo" where things are genuinely better.
Four Agile Steps:
- Align
Why are we going to Agile? It's not just to "do" Agile. Goal should be something like improve time to market, improve productivity, make happier customers, and have better quality.
- Learn
Everyone needs to understand Agile.
- Predict
We need to make things predictable before going faster.
- Accelerate
This is where we actually start getting better.
- Adapt
Try new things like Experiment Based Development
David had us do a small task in groups.
Why do so many companies struggle?
Most company think of Agile as a team level problem. Upper management just wants the team level to change, but not anything else. We need to change the System. We need to change the Organization, the leadership needs to understand Agility.
Three Impediments to Successful Agile Transformation
- Implementing solutions without clarity in desired results
This produces:
Lots of resistance and frustration
Silo Optimization
No clear measure of successWe did another exercise on how the importance of different tasks to transform a culture.
Steps to Organizational Change
a. Create Urgency - "We have to get better, or our company may go bust." (Comes for the top level) b. Form a powerful coalition c. Create a vision for change d. Communicate the vision e. Empower action f. Create quick wins g. Build on the change h. Anchor wins in culture
- No mechanism to resolve organizational level cross department impediments
a. Impediments not resolved quickly b. Resistance is empowered c. Teams hit a ceiling and become disenfranchised
Executives: We totally support agile, but what's the date, and what's the features?
- Leaders Not Creating Focus
If the leaders say all projects are equally important - the teams have no priorities.
So, the people with the least knowledge of corporate urgency, select the tasks that are coolest, easiest, and whose sponsor screams the loudest.
Impact: a. lots of interruptions b. No time to improve c. no flow d. no ability to forecast e. slow time to value
David showed us how Agile Velocity evaluates how an Agile transformation is going.
Approach Agile by asking why, get buy in, break into smaller things.
Note to Self: How to Use NUnit with C# .Net in Visual Studio for the Mac
Note to self: Download these from NuGet:
- NUnit
- Microsoft.NET.Test.Sdk
- NUnit3TestAdapter
Then select "Run/Run Unit Tests" and VS will create a runner in the bottom pane.
PS: Latest endpoint to connect Visual Studio to the Nuget.org repository is
https://api.nuget.org/v3/index.json
You can put these directly in the csproj:
<ItemGroup> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" /> <PackageReference Include="NUnit" Version="3.11.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.13.0" /> </ItemGroup>
Friday, April 12, 2019
Smallest example I could think of using C# Async/Await and HttpClient.GetAsync() with Generics
Smallest example I could think of using HttpClient.GetAsync() with Generics.
using System; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; using Newtonsoft.Json; namespace AsyncHttpClient { /// <summary> /// Tiny example of using HttpClient.GetAsync() with Generics. /// Uses the REST API calls from the most excellent mysafeinfo.com for presidents and Beatles albums /// This prints: /// Requesting presidents /// Requesting Beatles albums /// ... waiting ... /// first president = number: '1','', party: '', term: '' /// first Beatles album = album name: 'Please Please Me (Mono)', date: '1963-03-22T00:00:00' /// </summary> public class President { public int president; public string name, party, term; public override string ToString() { return $"number: '{president}','{name}', party: '{party}', term: '{term}'"; } } public class BeatlesAlbum { public string album, date; public override string ToString() { return $"album name: '{album}', date: '{date}'"; } } class AsyncHttpClientExample { private static void Main() { string presidentsUrl = "https://mysafeinfo.com/api/data?list=presidents&format=json"; string beatlesUrl = "https://mysafeinfo.com/api/data?list=beatlesalbums&format=json&select=ent,typ,rd&alias=ent=artist,typ=album,rd=date"; var asyncHttpClientExample = new AsyncHttpClientExample(); Console.Out.WriteLine("Requesting presidents"); var presidents = asyncHttpClientExample.GetAsync<List<President>>(presidentsUrl); Console.Out.WriteLine("Requesting Beatles albums"); var albums = asyncHttpClientExample.GetAsync<List<BeatlesAlbum>>(beatlesUrl); Console.Out.WriteLine("... waiting ..."); Console.Out.WriteLine("first president = {0}", presidents.Result[0]); Console.Out.WriteLine("first Beatles album = {0}", albums.Result[0]); } private async Task<T> GetAsync<T>(string url) { HttpClient client = new HttpClient(new HttpClientHandler()); HttpResponseMessage response = await client.GetAsync(url).ConfigureAwait(false); var jsonString = response.Content.ReadAsStringAsync().Result; T result = JsonConvert.DeserializeObject<T>(jsonString); return result; } } }
Thursday, February 21, 2019
Where to Find Your Tesla "Motor Vehicle Purchase Agreement"
The FAQ at Tesla is out of date as of Feb 21, 2019.
You can print it from your Tesla account.
1. Login to www.Tesla.com
2. In the top right-hand corner select "TESLA ACCOUNT" (what's with this ALL-CAPS trend?)
3. Select "Manage"
4. Under the car's picture select "View Details".
5. On the right side, near the bottom by "Motor Vehicle Purchase Agreement" select "View".
6. Your pdf of the "Motor Vehicle Purchase Agreement" will be displayed.
By the way, the tax form to get your $7,500 federal tax rebate is 8936.
Thursday, January 31, 2019
Random Notes on C#, Windows, Linux
.Net Core 2.0, to include an HTML fragment into a .cshtml page:
@await Html.PartialAsync("~/Views/Shared/_Address.cshtml")
To prepare for Dependency Injection in .Net Core 2.0
public void ConfigureServices(IServiceCollection services) { services.AddSingleton(provider => Configuration); services.AddTransient<IUserRepository, UserRepository>(); services.AddSingleton<IMailer, SmtpMailer>(); }
How to convert a json string to a C# Object
var myObject= JsonConvert.DeserializeObject(jsonString);
How to create a log4net factory outside of Startup.cs for unit testing.
public static ILoggerFactory GetLoggerFactory() { var loggerFactory = new LoggerFactory(); loggerFactory.AddProvider(new Log4NetProvider()); loggerFactory.AddDebug(); loggerFactory.AddConsole(GetTestConfiguration().GetSection("Logging")); loggerFactory.AddLog4Net("log4net.config"); return loggerFactory; }
Create simple Moq object in C#
var imailerMoq = new Mock(); imailerMoq.Setup(x => x.SendEmail(It.IsAny (), It.IsAny ())).Returns(true);
How to return async task for a unit test
public async TaskGetAwesomeString() { return await Task.FromResult("I'm the awesome returned text"); }
sudo -s //makes the entire session root
In C# you cannot downcast an object, only cast an object upwards:
wrong Sheep sheep = (sheep)mammal; right Mammal mammal = (Mammal)sheep;
C# -- to get prettyprint of json object with indentation:
var json = JsonConvert.SerializeObject(myObject, Formatting.Indented);
C# to get a key from a value:
Dictionary dictionary = GetMyDictionary(); var name = dictionary.FirstOrDefault(x => x.Value == id).Key;
To change the prompt in linux:
echo "PS1='\w\$ '" >> ~/.bash_profile; source ~/.bash_profile
Wednesday, January 30, 2019
Personal Notes from Udemy Course "ASP.NET Core 2.0"
Here are my notes for my future reference from Jonas Fagerberg's excellent Udemy Course. I would highly recommend you go buy the course: "ASP.NET Core 2.0"
Chapter 3 - MVC
Startup.cs - Let's get wired up!
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using AspNetCoreVideoCourse.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace AspNetCoreVideoCourse { public class Startup { public IConfiguration Configuration { get; set; } public Startup() { Configuration = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .Build(); } public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddSingleton(provider => Configuration); services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, IMessageService messageService) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); app.Run(async (context) => { await context.Response.WriteAsync(messageService.GetMessage()); }); } } }
Explicit Attribute Routing
namespace AspNetCoreVideoCourse.Controllers { [Route("[controller]")] public class EmployeeController { [Route("[action]")] public string Name() { return "Jonas"; } [Route("[action]")] public string Country() { return "Sweden"; } [Route("")] [Route("[action]")] public string Index() { return "Hello from Employee"; } } }
Generalized Attribute Routing:
namespace AspNetCoreVideoCourse.Controllers { [Route("company/[controller]/[action]")] public class EmployeeController { public string Name() { return "Jonas"; } public string Country() { return "Sweden"; } [Route("")] public string Index() { return "Hello from Employee"; } } }
To return json data directly to the browser:
public class HomeController : Controller { public ObjectResult Index() { var model = new Video {Id = 1, Title = "Shreck"}; return new ObjectResult(model); } }
To display an IEnumerable in Razor
@model IEnumerable<AspNetCoreVideoCourse.Models.Video> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Video</title> </head> <body> <table> @foreach (var video in Model) { <tr> <td>@video.Id</td> <td>@video.Title</td> </tr> } </table> </body> </html>
Chapter 5: Models
Creating an object through POST Example
Data annotations are found in System.ComponentModel.DataAnnotations.
The most common are:MinLength,MaxLength,Range, RegularExpression, Display, DataType, Required, Compare
Example
in Video.cs public class Video { public int Id { get; set; } [Required, MinLength(3)] [DataType(DataType.Password)] public string Title { get; set; } [Display(Name = "Film Genre")] public Genres Genre { get; set; } } in ViewModels/ViedoEditViewModel.cs: namespace AspNetCoreVideoCourse.ViewModels { public class VideoEditViewModel { public int Id { get; set; } [Required, MinLength(3), MaxLength(80)] public string Title { get; set; } public Genres Genre { get; set; } } } in HomeController.cs: HttpGet] public IActionResult Create() { return View(); } [HttpPost] public IActionResult Create(VideoEditViewModel model) { if (ModelState.IsValid) { var video = new Video { Title = model.Title, Genre = model.Genre }; _videoData.Add(video); return RedirectToAction("Details", new {id = video.Id}); } return View(); } in Views/Home/Create.cshtml: @using AspNetCoreVideoCourse.Models @model AspNetCoreVideoCourse.Entities.Video @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers <h2>Create Video</h2> <form asp-action="Create" method="post"> <div asp-validation-summary="All"></div> <table> <tr> <td><label asp-for="Title"></label></td> <td><input asp-for="Title"/></td> <td><span asp-validation-for="Title"></span></td> </tr> <tr> <td><label asp-for="Genre"></label></td> <td><select asp-for="Genre" asp-items="Html.GetEnumSelectList<Genres>()"></select></td> <td><span asp-validation-for="Genre"></span></td> </tr> </table> <input type="submit" value="Create"/> </form> <div><a asp-action="Index">Back to List</a></div>
Entity Framework
in package manager:
PM> add-Migration cmdlet Add-Migration at command pipeline position 1 Supply values for the following parameters: Name: Initial PM> update-database
Additional Files:
In Startup.cs: public class Startup public IConfiguration Configuration { get; set; } public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: true); if (env.IsDevelopment()) { builder.AddUserSecrets<Startup>(); } Configuration = builder.Build(); } public void ConfigureServices(IServiceCollection services) { var conn = Configuration.GetConnectionString("DefaultConnection"); services.AddDbContext<VideoDbContext>(options => options.UseSqlServer(conn)); services.AddMvc(); services.AddSingleton(provider => Configuration); services.AddSingleton<IMessageService, ConfigurationMessageService>(); services.AddScoped<IVideoData, SqlVideoData>(); } In SqlVideoData.cs: : using System.Collections.Generic; using AspNetCoreVideoCourse.Data; using AspNetCoreVideoCourse.Entities; namespace AspNetCoreVideoCourse.Services { public class SqlVideoData : IVideoData { private VideoDbContext _db; public SqlVideoData(VideoDbContext db) { _db = db; } public IEnumerable<Video> GetAll() { return _db.Videos; } public Video Get(int id) { return _db.Find<Video>(id); } public void Add(Video newVideo) { _db.Add(newVideo); _db.SaveChanges(); } } } in VideoDbContext.cs: using AspNetCoreVideoCourse.Entities; using Microsoft.EntityFrameworkCore; namespace AspNetCoreVideoCourse.Data { public class VideoDbContext : DbContext { public DbSet<Video> Videos { get; set; } public VideoDbContext(DbContextOptions<VideoDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); } } }
To Add an "Edit" View
in Edit.cshtml: <form asp-action="Edit" method="post"> <div asp-validation-summary="All"></div> <table> <tr> <td><label asp-for="Title"></label></td> <td><input asp-for="Title" /></td> <td><span asp-validation-for="Title"></span></td> </tr> <tr> <td><label asp-for="Genre"></label></td> <td><select asp-for="Genre" asp-items="Html.GetEnumSelectList<Genres>()"></select></td> <td><span asp-validation-for="Genre"></span></td> </tr> </table> <input type="submit" value="Edit" /> </form> in HomeController.cs: [HttpGet] public IActionResult Edit(int id) { var video = _videoData.Get(id); if (video == null) { return RedirectToAction("Index"); } return View(video); } [HttpPost] public IActionResult Edit(int id, VideoEditViewModel model) { var video = _videoData.Get(id); if (video == null || !ModelState.IsValid) return View(model); video.Title = model.Title; video.Genre = model.Genre; _videoData.Commit(); return RedirectToAction("Details", new {id = video.Id}); } in SqlVideoData.cs: using System.Collections.Generic; using AspNetCoreVideoCourse.Data; using AspNetCoreVideoCourse.Entities; namespace AspNetCoreVideoCourse.Services { public class SqlVideoData : IVideoData { private VideoDbContext _db; public SqlVideoData(VideoDbContext db) { _db = db; } public IEnumerable<Video> GetAll() { return _db.Videos; } public Video Get(int id) { return _db.Find<Video>(id); } public void Add(Video newVideo) { _db.Add(newVideo); _db.SaveChanges(); } public int Commit() { return _db.SaveChanges(); } } }
Section 7 Razor Views
_ViewStart.cshtml will define variables for all pages in lower directories _ViewImports.cshtml will define import statements for all lower pages
Partial Views
@Html.Partial("_Video", video); @await Html.PartialAsync("_Video", video);
Components
Components allow you to inject html from code.
in Views/Shared/Components/Message/Default.cshtml: using AspNetCoreVideoCourse.Services; using Microsoft.AspNetCore.Mvc; namespace AspNetCoreVideoCourse.ViewComponents { public class Message : ViewComponent { private readonly IMessageService _message; public Message(IMessageService message) { _message = message; } public IViewComponentResult Invoke() { var model = _message.GetMessage(); return View("Default", model); } } } in Views/Shared/_Layout.cs: <footer> @RenderSection("footer",false) @await Component.InvokeAsync("Message") </footer>
Section 8: Forms Authentication / Identity Management
in AccountController: using System.Threading.Tasks; using AspNetCoreVideoCourse.Entities; using AspNetCoreVideoCourse.ViewModels; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; namespace AspNetCoreVideoCourse.Controllers { public class AccountController : Controller { private readonly UserManager<User> _userManager; private readonly SignInManager<User> _signInManager; public AccountController(UserManager<User> userManager, SignInManager<User> signInManager) { _userManager = userManager; _signInManager = signInManager; } [HttpGet] public IActionResult Register() { return View(); } [HttpPost] public async Task<IActionResult> Register(RegisterViewModel model) { if (!ModelState.IsValid) return View(); var user = new User {UserName = model.Username}; var result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded) { await _signInManager.SignInAsync(user, false); return RedirectToAction("Index", "Home"); } else { foreach (var error in result.Errors) { ModelState.AddModelError("",error.Description); } } return View(); } [HttpPost] public async Task<IActionResult> Logout() { await _signInManager.SignOutAsync(); return RedirectToAction("Index", "Home"); } [HttpGet] public IActionResult Login(string returnUrl = "") { var model = new LoginViewModel {ReturnUrl = returnUrl}; return View(model); } [HttpPost] public async Task<IActionResult> Login(LoginViewModel model) { if (!ModelState.IsValid) return View(model); var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberMe, false); if (result.Succeeded) { if (!string.IsNullOrEmpty(model.ReturnUrl) && Url.IsLocalUrl(model.ReturnUrl)) { return Redirect(model.ReturnUrl); } else { return RedirectToAction("Index", "Home"); } } ModelState.AddModelError("","Login failed"); return View(model); } } } in Views/Account/Login: @model LoginViewModel @{ ViewBag.Title = "Login";} <h2>Login</h2> <form method="post" asp-controller="Account" asp-action="Login" asp-route-returnurl="@Model.ReturnUrl"> <div asp-validation-summary="ModelOnly"></div> <div> <label asp-for="Username"></label> <input asp-for="Username"/> <span asp-validation-for="Username"></span> </div> <div> <label asp-for="Password"></label> <input asp-for="Password"/> <span asp-validation-for="Password"></span> </div> <div> <label asp-for="RememberMe"></label> <input asp-for="RememberMe"/> <span asp-validation-for="RememberMe"></span> </div> <div> <input type="submit" value="Register"/> </div> </form> in Views/Account/Register: @model RegisterViewModel @{ ViewBag.Title = "Register";} <h1>Register</h1> <form method="post" asp-controller="Account" asp-action="Register"> <div asp-validation-summary="ModelOnly"></div> <div> <label asp-for="Username"></label> <input asp-for="Username"/> <span asp-validation-for="Username"></span> </div> <div> <label asp-for="Password"></label> <input asp-for="Password"/> <span asp-validation-for="Password"></span> </div> <div> <label asp-for="ConfirmPassword"></label> <input asp-for="ConfirmPassword"/> <span asp-validation-for="ConfirmPassword"></span> </div> <div> <input type="submit" value="Register"/> </div> </form> in ViewModels/LoginViewModel.cs: using System.ComponentModel.DataAnnotations; namespace AspNetCoreVideoCourse.ViewModels { public class LoginViewModel { [Required] public string Username { get; set; } [Required, DataType(DataType.Password)] public string Password { get; set; } public string ReturnUrl { get; set; } [Display(Name = "Remember Me")] public bool RememberMe { get; set; } } } in ViewModels/RegisterViewModel.cs: using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; namespace AspNetCoreVideoCourse.ViewModels { public class RegisterViewModel { [Required, MaxLength(255)] public string Username { get; set; } [Required, DataType(DataType.Password)] public string Password { get; set; } [Required, DataType(DataType.Password), Compare(nameof(Password))] public string ConfirmPassword { get; set; } } } in Views/Shared/_LoginLinks.cshtml: @using Microsoft.AspNetCore.Identity @inject SignInManager<User> SignInManager @inject UserManager<User> UserManger @if (SignInManager.IsSignedIn(User)) { <div>@User.Identity.Name</div> <form method="post" asp-controller="Account" asp-action="Logout"> <input type="submit" value="Logout"/> </form> } else { <a asp-controller="Account" asp-action="Login">Login</a> <a asp-controller="Account" asp-action="Register">Register</a> }
Austin .Net User's Group - Jan 14, 2018 - Shawn Weisfeld on the Future of DevOps
Shawn Weisfeld, Cloud Solution Architect with Microsoft, gave a great presentation on Azure DevOps to 30 people at Austin .Net User's Group. The video is at usergroup.tv/videos/devops-in-a-cloud-world-2.
What is Dev Ops? "DevOps is the union of people, process, and products to enable continuous delivery of value to your end users."
He showed a very fun youtube video of Formula One Pit Stop 1950, 2014 demonstrating the promise of DevOps.
40-50% of Azure machines are Linux. Microsoft is taking a strong agnostic stand on operating systems, which is good for the community and good from Microsoft. It's refreshing to see them being even handed with OSes.
To me the most informative subject Shawn covered was that Visual Studio Online and other tools are being rebranded as Azure DevOps
Here's the Workflow:
Azure Boards - takes the place of tfs Azure Repos Azure Pipelines Azure Test Plans Azure Artifacts
Shawn used a tool to zoom in during the demo from zoomit.com
We had a discussion towards the end of his talk about "Infrastructure as Code", meaning you can write code to write the descriptions of containers and them launch those containers, so it's all software.
Tuesday, January 29, 2019
Java User's Group - Jan 29th, 2019 - The Future of Java
Simon Ritter, Deputy CTO, from Azul Systems gave a great presentation to 100 java developers about new things in Java 9,10,11, and 12. Slides are at www.slideshare.net/SimonRitter/moving-towards-jdk-12.
I did java programming 12 years ago and it was great fun to come back to the Java User's Group to see old friends again. Currently I'm doing C# .Net Core work, but I wanted to see what Java has been faring.
TL;DR: My impressions: Java is going to face headwinds with Oracle requiring money for licenses for production versions of JDK and beyond. Especially for small shops it's just easier to spin up a container with all open source and not worry about payments. Many organizations will stick with older free versions of Java (which is where Azul can make some money and help the community), but after a while, do you want to be on older versions of a language while the world is moving forward? It will be like watching ice melt on a 33 degree day, but we will see a slow abandonment of Java.
Java is still playing catchup with C# on features like "var", expanding switch statements, and raw string literals, but it's good to see the progress.
Here's my random, jumbled notes:
JDK 9, September 2017 86 new items. Oracle says JDK 9 was the last big release.
Java Platform Module System (JPMS) (JEP 220) breaks the 4,500 classes in Java into smaller chunks; with Modules you can create a runtime specific for your application only including modules needed for the app.
jlink (JEP 282) creates the java hierarchy with a smaller set of modules.
Instead of a release every two years, Oracle will release new JDKs twice a year, once in March and once in September. With so many releases, only certain ones will have long term support.
In JDK 11, some parts of the JDK will be open sourced like Flight recorder and Mission control. Some commercial features will be removed like JavaFX.
Java 8 had 350 methods deprecated, but never removed. JDK 9 removed six methods and one class (JavaBeans had a dependency on the desktop). JDK 10 removed 1 package, 6 classes, 9 methods and 1 field.
Compatibility not guaranteed in the future. Developers will have one release (six months) warning of deprecated.
Oracle JDK binary has LTS versions like 11, 17; Oracle OpenJDK does not.
Oracle JDK 11 has new license. Must have a paid-for license from Oracle for production for JavaSE. JDK 8 can be used forever for free, but without any further security patches and bug fixes.
What's new in JDK 10
Local Variable Type Inference (JEP 286) Java gets "var", infers type (like C#). "var" is not a reserved word, just a reserved type (meaning you can't create a class named "var").
JEP 307: Parallel Full GC for G1
JEP 310: Application Class-Data Sharing. Write java "schema" info to a file, to be read next time to speed startup.
JEP 317: JIT compiler (Graal)
Root Certificates, Heap allocation on other devices, remove javah tool, Garbage Collector Interface (Red Hat), Thread-Local Handshakes.
73 New APIs, like the collections List, Set, Map get a static copyOf() method to get an immutable copy.
What's new in JDK 11
17 JEPs, 3 from outside Oracle, like Red Hat's JEP 318 Epsilon garbage collector.
JEP 323: Local-variable syntax for lambda parameters.
JEP 327: new Unicode 10 Support for 8,518 new characters.
JEP 330: Launch Single file source code. Can launch a single file like "$java Factorial.java 4"
Many security features
Nashorn JavaScript engine deprecated
New I/O methods like nullInuptStream
String has new methods like isBlank(), repeat(int), strip()
Predicate now has Predicate.not()
What's new in JDK 11
Six modules removed, including java.corba, java.transaction, java.activation, java.xml.bind, java.xml.ws, java.xml.ws.annotation
Removes 27 command line flags and added 53
JDK 12 - A Small Release
JEP 325: Switch Expressions (Preview)
JEP 189: Shenandoah GC
JEP 334, 230, 341
New APIs: teeing(Collector, Collector, joinerFunc)
Class - describeConstable
Long Term Future
Project Amber, how to simplifying Java Language syntax. Kotlin is popular due to its clean syntax.
JEP 302: Lambda bits, single underscore for unused jparameters in lambda
JEP 326: Raw string literals, use backtick to start raw strings
JEP 305: Pattern Matching
Project Valhalla
Primitives are good for performance, objects good for OO concepts
Can have collections of primitives
Value types, are immutable, really
Project Loom
Loom introduces "fibres" which are lighter weight threads, less memory used, lower overhead
Zulu Java
Zulu community - Free versions of Open versions.
Zulu Enterprise - For money you can get backports of bug fixes and security patches from latest OpenJDK to previous releases.
Questions?
What is the effect of Oracle's new licensing pricing on the cloud? Cloud providers will provide support.
No more free JDK 11 from Oracle.
<Thursday, January 17, 2019
Random Cheatsheet (mostly C# .net core)
Latest endpoint to connect Visual Studio to the Nuget.org repository is
https://api.nuget.org/v3/index.json
.Net Core 2.0, to include an HTML fragment into a .cshtml page:
@await Html.PartialAsync("~/Views/Shared/_Address.cshtml")
To prepare for Dependency Injection in .Net Core 2.0
public void ConfigureServices(IServiceCollection services) { services.AddSingleton(provider => Configuration); services.AddTransient<IUserRepository, UserRepository>(); services.AddSingleton<IMailer, SmtpMailer>(); }
How to convert a json string to a C# Object
var myObject= JsonConvert.DeserializeObject(jsonString);
How to create a log4net factory outside of Startup.cs for unit testing.
public static ILoggerFactory GetLoggerFactory() { var loggerFactory = new LoggerFactory(); loggerFactory.AddProvider(new Log4NetProvider()); loggerFactory.AddDebug(); loggerFactory.AddConsole(GetTestConfiguration().GetSection("Logging")); loggerFactory.AddLog4Net("log4net.config"); return loggerFactory; }
Create simple Moq object in C#
var imailerMoq = new Mock(); imailerMoq.Setup(x => x.SendEmail(It.IsAny (), It.IsAny ())).Returns(true);
How to return async task for a unit test
public async TaskGetAwesomeString() { return await Task.FromResult("I'm the awesome returned text"); }
sudo -s //makes the entire session root
In C# you cannot downcast an object, only cast an object upwards:
wrong Sheep sheep = (sheep)mammal; right Mammal mammal = (Mammal)sheep;
C# -- to get prettyprint of json object with indentation:
var json = JsonConvert.SerializeObject(myObject, Formatting.Indented);
C# to get a key from a value:
Dictionary dictionary = GetMyDictionary(); var name = dictionary.FirstOrDefault(x => x.Value == id).Key;
To change the prompt in linux:
echo "PS1='\w\$ '" >> ~/.bash_profile; source ~/.bash_profile
Wednesday, January 16, 2019
A TestDriven Workshop Example Using C# and NUnit
I've done this workshop multiple times at work to teach developers Test Driven Development using C# and NUnit.
You can clone it at https://github.com/fincher42/TDDWorkshopNunit.git
The theme of the workshop is from the movie "We Bought A Zoo".
Enjoy and leave me feedback below on how to improve the workshop.
Here's an outline of my notes:
Essence of TDD: Write failing tests **first**, before coding the functionality.
Ping Pong
- Bob writes a failing test
- Ashley writes just enough functionality in the method so it will pass.
- The code may then be refactored to make it cleaner.
- Bob and Ashley now switch roles and continue.
This is the Red/Green/Refactor cycle.
One method of arranging your code is to have Arrange/Act/Assert sections in your test.
Benefits of Test Driven Development:
- Encourages better architectural design
- Makes debugging easier
- Guarantees tests are written
- Encourages us to think about requirements and edge cases
- Let's you be courageous and refactor code
Drawbacks of Test Driven Development:
- Tests are expensive. They are expensive to write and more expensive to maintain.
- Perfect Unit Tests with 100% coverage do not offer any guarantees on overall code quality. Don't be lulled into a sense of false security.
- GUI, Integration, Performance, and Endurance tests are also needed.
Thursday, January 10, 2019
The Four Biggest Changes in Software Development in the Last 40 Years
I was giving a workshop on Test Driven Development today. Being a history nerd (don't get me started about the causes of the fall of the Roman Empire), I was reflecting back on how much has changed in software and how much hasn't. I started programming 42 years ago on punched cards. Here's my list of the most game changing developments in software in the last 40 years.
- Duh, It's the Internet
- Computers are so much faster.
- Interactive Development Environments (IDE)
- Test Driven Development (TDD)
Being able to use Stackoverflow and its kin, we can peruse the minds of thousands of people and find a solution quickly. Online training courses are available to teach us the latest software. It's simply amazing how much more we can create and learn.
With punched cards at Texas Tech University in the fall of 1976, a diligent student could get in five compile/executes cycles a day. Five. Now you can do that in a few minutes. This changes the way we develop software. Instead of mapping out your entire program on quadral paper using the IBM flowchart template with a Pentel mechanical pencil, we can start programming and build the software iteratively.
Having an IDE that can pop-up all the available methods on an object is such a time saver. Having Resharper to refactor code on the fly, perfectly, is such an asset.
Test Driven Development encourages us to write software that is easy to test, but more importantly, it demands a layered architecture and encourages small modules. TDD gives us the courage to do massive refactoring. Thank you Kent Beck.
My major professor at Tech use to tell us about a principle of good software engineering, but follow it up with "But, of course, this doesn't matter if you have really good people." That is still true today. The heart of producing good software is excellent people with small egos who have a passion to hone their craft and cooperate with their peers.